2010-07-30 9 views
17

Supongamos que tengo una función que toma argumentos variados (...) o un va_list pasado desde otra función. La lógica principal está en esta función en sí (llamémoslo f1), pero quiero que pase el va_list a otra función (llamémoslo f2) que determinará el siguiente tipo de argumento, obténgalo usando va_arg, convierta y convierta correctamente guárdelo para que lo use la persona que llama.Pase va_list o puntero a va_list?

Es suficiente pasar una va_list a f2, o es necesario pasar un puntero a va_list. A menos que se requiera va_list para ser un tipo de matriz o almacenar sus datos de posición en la ubicación a la que apunta el objeto va_list (en lugar de en el objeto mismo), no puedo ver cómo el paso por valor podría permitir la función de llamada (f1) para 'ver' los cambios de la función llamada realizada por va_arg.

¿Alguien puede arrojar luz sobre esto? Me interesa lo que exige el estándar, no lo que permite una implementación particular.

Respuesta

23

Parece que tendrá que pasar un puntero a la lista va_. Para más información, véase la sección C99 standard document 7.15.In particular, el punto bullet 3 estados:

El ap objeto puede ser pasa como 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 pasa a la va_end macro antes de cualquier referencia adicional a ap

[mis cursiva]

Editar: di cuenta de una nota al pie en la norma:

215) está permitido crear un puntero a una va_list y pasar a ese puntero otra función, en la que caso la función original puede hacer un mayor uso de la lista original después de la otra función devuelve

lo que puede pasar un puntero a la va_list y hacer va_arg(*va_list_pointer) en la función llamada.

+0

De acuerdo con su última edición: un puntero es el camino a seguir (ya que el OP quiere que los cambios en 'va_list' sean definitivamente visibles en la función de llamada). – caf

+0

@caf: no creo que debas haber editado mi referencia a 'vfprintf()' porque parece que otros están cometiendo el mismo error que yo y sugiriendo que el que pregunta mira los prototipos existentes (lo que en realidad no es cierto) responde su pregunta). – JeremyP

+2

Yo diría que dejo un comentario y/o los voto abajo entonces - parece mejor que la respuesta correcta no se ofusque con la suposición incorrecta anterior ... – caf

2

En mi entender, se supone que debes pasar el va_list directamente (no un puntero). Esto parece estar apoyada por comp.lang.c:.

"Un va_list no es en sí una lista de argumentos variable, es realmente una especie de puntero a uno Es decir, una función que acepta un va_list no es en sí varargs, ni el vicio versa. "

+0

No creo que la cita respalde su afirmación. Nada sobre esto impide pasar un puntero a una 'va_list', y de hecho el estándar dice explícitamente que esto está permitido. – caf

2

Encuentro los textos bastante ambiguos sobre esta pregunta. El más simple es quizás buscar 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.

+1

Las funciones estándar no están destinadas a ser llamadas en la forma en que OP quiere: después de que se llaman, la 'va_list' ya no se puede usar y solo se debe pasar a' va_end() '. – caf

+0

De hecho, soy el OP y estoy de acuerdo con caf en este caso. JeremyP es el único que parece haber citado alguna evidencia y el estándar es bastante claro: debes pasar un puntero para la semántica que quiero. –

0

Funciones en estándar pase biblioteca va_list elemento C en sí (man 3 vprintf):

#include <stdarg.h> 

    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); 
+1

Ninguna de estas funciones está pensada para ser llamada de la manera que OP quiere: después de que se invoquen estas funciones, la 'va_list' ya no se puede usar y solo se debe pasar a' va_end() '. – caf

0

pasar un puntero a va_list funciona bien en el sistema de 32 bits. Incluso puede buscar un parámetro por vez en la subrutina. Pero parece que no funciona en el sistema de 64 bits, producirá un error de segmento en va_arg().

Cuestiones relacionadas