Digamos que tengo una función C que toma un número variable de argumentos: ¿Cómo puedo llamar a otra función que espera un número variable de argumentos dentro de ella, pasando todos los argumentos que entraron en la primera función?
Ejemplo:
void format_string(char *fmt, ...);
void debug_print(int dbg_lvl, char *fmt, ...) {
format_string(fmt, /* how do I pass all the arguments from '...'? */);
fprintf(stdout, fmt);
}
c
variadic-functions
Vicent Marti
fuente
fuente
Respuestas:
Para pasar los puntos suspensivos, debes convertirlos en va_list y usar esa va_list en tu segunda función. Específicamente;
fuente
format_string
será útil, ya que tendría que hacer modificaciones in situ a fmt, lo que ciertamente tampoco debería hacerse. Las opciones incluirían deshacerse de format_string por completo y usar vfprintf, pero eso hace suposiciones sobre lo que format_string realmente hace, o que format_string devuelva una cadena diferente. Editaré la respuesta para mostrar la última.argptr
y la función llamada usa la funciónargptr
, lo único seguro es llamarva_end()
y luego reiniciarva_start(argptr, fmt);
para reiniciar. O puede usarlova_copy()
si su sistema lo admite (C99 y C11 lo requieren; C89 / 90 no).No hay forma de llamar a (por ejemplo) printf sin saber cuántos argumentos le está pasando, a menos que quiera meterse en trucos traviesos y no portátiles.
La solución utilizada generalmente es proporcionar siempre una forma alternativa de funciones vararg, por lo que
printf
tienevprintf
que tiene unava_list
en lugar de la...
. Las...
versiones son solo envoltorios alrededor de lasva_list
versiones.fuente
vsyslog
es compatible con POSIX .Las funciones variables pueden ser peligrosas . Aquí hay un truco más seguro:
fuente
#define callVardicMethodSafely(values...) ({ values *v = { values }; _actualFunction(values, sizeof(v) / sizeof(*v)); })
En el magnífico C ++ 0x podría usar plantillas variadas:
fuente
Puede usar el ensamblaje en línea para la llamada a la función. (en este código supongo que los argumentos son caracteres).
fuente
Puedes probar macro también.
fuente
Aunque puede resolver pasar el formateador almacenándolo primero en el búfer local, pero eso necesita apilarse y en algún momento puede ser un problema para tratar. Intenté seguir y parece funcionar bien.
Espero que esto ayude.
fuente
La solución de Ross se limpió un poco. Solo funciona si todos los argumentos son punteros. Además, la implementación del lenguaje debe admitir la eliminación de la coma anterior si
__VA_ARGS__
está vacía (tanto Visual Studio C ++ como GCC lo hacen).fuente
Digamos que tiene una función variadic típica que ha escrito. Porque se requiere al menos un argumento antes del variable
...
, siempre debe escribir un argumento adicional en uso.O tu
Si ajusta su función variadic en una macro, no necesita argumentos anteriores. Considere este ejemplo:
Obviamente, esto es mucho más conveniente, ya que no es necesario especificar el argumento inicial cada vez.
fuente
No estoy seguro de si esto funciona para todos los compiladores, pero ha funcionado hasta ahora para mí.
Puede agregar el ... a inner_func () si lo desea, pero no lo necesita. Funciona porque va_start usa la dirección de la variable dada como punto de inicio. En este caso, le estamos dando una referencia a una variable en func (). Entonces usa esa dirección y lee las variables después de eso en la pila. La función inner_func () está leyendo desde la dirección de pila de func (). Por lo tanto, solo funciona si ambas funciones usan el mismo segmento de pila.
Las macros va_start y va_arg generalmente funcionarán si les das alguna var como punto de partida. Entonces, si lo desea, puede pasar punteros a otras funciones y usarlas también. Puede hacer sus propias macros fácilmente. Todo lo que hacen las macros es escribir direcciones de memoria. Sin embargo, hacer que funcionen para todos los compiladores y llamar a convenciones es molesto. Por lo tanto, generalmente es más fácil usar los que vienen con el compilador.
fuente