Poblando una va_list

¿Hay alguna manera de crear una va_list desde cero? va_list llamar a una función que toma una va_list como parámetro:

 func(void **entry, int num_args, va_list args, char *key); 

… desde una función que no toma una cantidad variable de argumentos. La única forma en que puedo pensar es en crear una función intermedia que tome varargs y luego pase su va_list, lo cual es bastante estúpido:

 void stupid_func(void **entry, char *key, int num_args, ...) { va_list args; va_start(args, num_args); func(entry, num_args, args, key); va_end(args); } 

¿Hay una mejor manera? No puedo cambiar la firma de func .

Esta es una mala idea porque la abstracción va_list está ahí para ocultar algunos detalles específicos del comstackdor / architecture sombrío con respecto a stack-pointers y lo que no. Y está prácticamente ligado al scope de la función una vez inicializado. Si enrollas la stack y haces referencia a marcos anteriores va_args fuera del scope, las cosas pueden ir mal. Puedes pasarlos pero …

esperar errores

Ver: http://lists.freebsd.org/pipermail/freebsd-amd64/2004-August/001946.html

Además, checkout man (3) va_copy y friends para un manejo más seguro de va_args y pasándoselos.

En mi humilde opinión, las cosas va_args no son muy claras. En el pasado he tratado esto inicializando estructuras / punteros opacos en el montón y luego usando la aritmética del puntero para trabajar los datos. Pero esto es un truco y depende de las circunstancias.

Entiendo y acepto las advertencias de Aiden: va_list y amigos son peligrosos ya que ocultan las convenciones de llamadas de bajo nivel. Pero … en esta situación, creo que no tienes otra opción. Ponga la función static ... en el archivo .c para que nadie más pueda verla, como un proxy para la función a la que necesita llamar, haga una prueba al máximo y termine. Solo asegúrate de no exponer los argumentos variados en la cadena de llamadas.

Su idea de una función proxy que cree la lista va_list es la forma correcta de hacerlo. No es necesario que ese proxy tenga scope público. Sin embargo, si puede encontrar que el proxy ya existe. Por ejemplo, en muchas implementaciones de bibliotecas, sprintf() es solo un proxy para vsprintf() .

A menos que esté dispuesto a vincular su código a un comstackdor específico y una plataforma de destino, no hay mejor manera. Los nombres definidos en están ahí para proporcionar una interfaz portátil y coherente para admitir el acceso a listas de argumentos variadic. La única forma portátil de implementar y usar funciones variadic es a través de esa interfaz.

Dicho esto, es posible que sacrifique la portabilidad duplicando un marco de llamada en una matriz y construya una lista va_list que lo haga referencia correctamente. El resultado nunca será portátil.

Hay una publicación de blog útil sobre cocoawithlove que sugiere una forma de falsificar una lista va: lo bloquea al comstackdor y al comportamiento específico de la plataforma, como se observa en las otras buenas respuestas aquí.

Tu stupid_func es un código C perfectamente válido, de lo contrario, ¿cómo supuestamente llamarías vprintf y funciones similares?

La biblioteca glib hace uso de estas envolturas extensivamente. La especificación C99 tiene algo similar en los ejemplos. Extracto de la sección 7.19.6.8 :

A continuación, se muestra el uso de la función vfprintf en una rutina general de informe de errores.

 #include  #include  void error(char *function_name, char *format, ...) { va_list args; va_start(args, format); // print out name of function causing error fprintf(stderr, "ERROR in %s: ", function_name); // print out remainder of message vfprintf(stderr, format, args); va_end(args) }