¿Pasar va_list o puntero a va_list?

Supongamos que tengo una función que toma argumentos variadic ( ... ) o un va_list pasado de otra función va_list . La lógica principal está en esta función en sí misma (llamémosla f1 ), pero quiero que pase la va_list a otra función (llamémosla f2 ) que determinará el siguiente tipo de argumento, la va_arg usando va_arg , y convertiremos guárdelo para que lo use la persona que llama.

¿Es suficiente pasar un va_list a f2 , o es necesario pasar un puntero a va_list? A menos que se requiera que va_list sea un tipo de matriz o, de lo contrario, almacene sus datos de posición en la ubicación a la que va_list objeto va_list (en lugar de en el propio objeto), no puedo ver cómo pasarlo por valor podría permitir la función de llamada ( f1 ) Para ‘ver’ los cambios de la función llamada realizados por va_arg .

¿Alguien puede arrojar luz sobre esto? Me interesa lo que requiere la norma, no lo que permite alguna implementación particular.

Parece que necesitarás pasar un puntero a la lista va_. Para obtener más información, consulte la sección 7.15 del documento estándar de C99. En particular, el punto 3 indica:

El objeto ap puede pasarse como un argumento a otra función; si esa función invoca la macro va_arg con el parámetro ap, el valor de ap en la función de llamada es indeterminado y se pasará a la macro va_end antes de cualquier referencia adicional a ap

[mis cursivas]

Edición: Acabo de notar una nota al pie en el estándar:

215) Se permite crear un puntero a una lista de va y pasar ese puntero a otra función, en cuyo caso la función original puede seguir usando la lista original después de que la otra función retorne.

Por lo tanto, puede pasar un puntero a la lista de va y hacer va_arg(*va_list_pointer) en la función llamada.

En mi opinión, se supone que debes pasar la lista va_ directamente (no un puntero a ella). Esto parece ser soportado por comp.lang.c :

“Una lista_de_vista no es en sí misma una lista de argumentos variables; es realmente una especie de puntero a uno. Es decir, una función que acepta una lista_vista no es en sí misma varargs, ni viceversa”.

Encuentro los textos bastante ambiguos en esta pregunta. Lo más simple es quizás observar en el estándar cómo se supone que las funciones predefinidas con va_list lo reciben, por ejemplo, vsnprintf . Y esto es claramente por valor y no por referencia.

Las funciones en la biblioteca estándar de C pasan el va_list elemento va_list ( man 3 vprintf ):

  #include  int vprintf(const char *format, va_list ap); int vfprintf(FILE *stream, const char *format, va_list ap); int vsprintf(char *str, const char *format, va_list ap); int vsnprintf(char *str, size_t size, const char *format, va_list ap); 

Pasar un puntero a va_list funciona bien en un sistema de 32 bits. Incluso puede obtener un parámetro por vez en la subrutina. Pero no parece funcionar en un sistema de 64 bits, producirá un fallo de segmento en va_arg ().