2010-08-20 20 views
71

Así que tienen 2 funciones que ambos tienen argumentos similaresPaso de argumentos variable a otra función que acepta una lista de argumentos variable

void example(int a, int b, ...); 
void exampleB(int b, ...); 

Ahora example llamadas exampleB, pero ¿cómo se puede pasar a lo largo de las variables de la lista de argumentos variable sin modificar exampleB (ya que esto ya se usa en otros lugares).

+5

posible duplicado de [Reenviar una invocación de una función variadic en C] (http://stackoverflow.com/questions/150543/forward-an-invocation-of-a-variadic-function-in-c) –

+0

Bien la solución en ese caso estaba usando vprintf, y ese no es el caso aquí. –

Respuesta

79

No puede hacerlo directamente; usted tiene que crear una función que toma un va_list:

#include <stdarg.h> 

static void exampleV(int b, va_list args); 

void example(int a, int b, ...) 
{ 
    va_list args; 
    va_start(args, b); 
    exampleV(b, args); 
    va_end(args); 
} 

void exampleB(int b, ...) 
{ 
    va_list args; 
    va_start(args, b); 
    exampleV(b, args); 
    va_end(args); 
} 

static void exampleV(int b, va_list args) 
{ 
    ...whatever you planned to have exampleB do... 
    ...except it calls neither va_start nor va_end... 
} 
+1

Se sospecha que tuve que hacer algo como esto, el problema es que la función de ejemplo es básicamente una envoltura para vsprintf y no mucho más:/ –

+0

@Xeross: Tenga en cuenta que esto no cambia la especificación externa de lo que hace el ejemplo - simplemente cambia el interno implementación. No estoy seguro de cuál es el problema. –

+1

Lo he manejado de manera similar a esto, gracias. –

14

debe crear versiones de estas funciones que toman una va_list y las pasan. Mire vprintf como un ejemplo:

int vprintf (const char * format, va_list arg); 
-1

Usando el nuevo estándar C++ 0x, es posible que pueda conseguir este hecho uso de plantillas variadic o incluso convertir ese viejo código a la nueva sintaxis de la plantilla sin rompiendo cualquier cosa

+0

desafortunadamente esto no es posible en todas las instancias - simplemente intente usar lambdas – serup

0

Basándome en el comentario de que está ajustando vsprintf, y que está etiquetado como C++, sugeriría no intentar hacer esto, sino cambiar la interfaz para usar iostreams de C++. Tienen ventajas sobre la línea de funciones print, como seguridad de tipo y poder imprimir elementos que printf no podría manejar. Algunas modificaciones ahora podrían ahorrar una gran cantidad de dolor en el futuro.

+0

¿A qué ventajas se refiere? – cjcurrie

+0

@cjcurrie: la ventaja es seguridad tipo, incluso con tipos definidos por el usuario. Por supuesto, las funciones C no pueden manejar tipos definidos por el usuario. –

2

Incidentalmente, muchas implementaciones C tienen una variación interna de v? Printf que en mi humilde opinión debería haber sido parte del estándar C. Los detalles exactos varían, pero una implementación típica aceptará una estructura que contenga un puntero de función de salida de caracteres e información que diga lo que se supone que sucederá. Esto permite que printf, sprintf y fprintf utilicen el mismo mecanismo 'core'. Por ejemplo, vsprintf podría ser algo como:

 
void s_out(PRINTF_INFO *p_inf, char ch) 
{ 
    (*(p_inf->destptr)++) = ch; 
    p_inf->result++; 
} 

int vsprintf(char *dest, const char *fmt, va_list args) 
{ 
    PRINTF_INFO p_inf; 
    p_inf.destptr = dest; 
    p_inf.result = 0; 
    p_inf.func = s_out; 
    core_printf(&p_inf,fmt,args); 
} 

La función core_printf llama entonces p_inf-> func para cada personaje, que debe emitirse; la función de salida puede enviar los caracteres a la consola, un archivo, una cadena u otra cosa. Si la implementación de uno expone la función core_printf (y cualquier mecanismo de configuración que utilice), se puede ampliar con todo tipo de variaciones.

1

también quería envolver printf y encontré una respuesta útil aquí:

How to pass variable number of arguments to printf/sprintf

que no era en absoluto interesado en el rendimiento (estoy seguro de que esta pieza de código se puede mejorar en una serie de maneras, sienten libres de hacerlo :)), esto es para debugprinting general solamente así que hice esto:

//Helper function 
std::string osprintf(const char *fmt, ...) 
{ 
    va_list args; 
    char buf[1000]; 
    va_start(args, fmt); 
    vsnprintf(buf, sizeof(buf), fmt, args); 
    va_end(args); 
    return buf; 
} 

que luego pueda usar como esto

Point2d p; 

cout << osprintf("Point2d: (%3i, %3i)", p.x, p.y); 
instead of for example: 
cout << "Point2d: (" << setw(3) << p.x << ", " << p.y << ")"; 

Los ostreams de C++ son hermosos en algunos aspectos, pero prácticamente se vuelven horribles si quieres imprimir algo como esto con algunas cadenas pequeñas como paréntesis, dos puntos y comas insertadas entre los números.

4

Tal throwin una roca en un estanque aquí, pero parece que funciona bastante bien con C++ 11 plantillas variadic:

#include <stdio.h> 

template<typename... Args> void test(const char * f, Args... args) { 
    printf(f, args...); 
} 

int main() 
{ 
    int a = 2; 
    test("%s\n", "test"); 
    test("%s %d %d %p\n", "second test", 2, a, &a); 
} 

Por lo menos, funciona con g++.

Cuestiones relacionadas