Pregunta Pasar argumentos variables a otra función que acepte una lista de argumentos variables


Entonces tengo 2 funciones que tienen argumentos similares

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

Ahora example llamadas exampleB, pero ¿cómo puedo pasar las variables en la lista de argumentos variables sin modificar exampleB (como esto ya se usa en otros lugares también).


75
2017-08-20 12:22


origen


Respuestas:


No puedes hacerlo directamente; tienes que crear una función que tenga 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...
}

89
2017-08-20 12:28



deberías crear versiones de estas funciones que toman una va_list y las pasan. Mirar vprintf como ejemplo:

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

15
2017-08-20 12:26



Tal vez tirar una piedra en un estanque aquí, pero parece funcionar bastante bien con las plantillas variadas de C ++ 11:

#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++.


9
2017-09-16 13:42



Incidentalmente, muchas implementaciones de C tienen una variación de v \ printf interna que en mi humilde opinión debería haber sido parte del estándar de 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 así 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 a p_inf-> func para cada carácter que se va a producir; 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.


2
2017-08-20 14:34



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

Cómo pasar el número variable de argumentos a printf / sprintf

No me interesaba en absoluto el rendimiento (estoy seguro de que este fragmento de código se puede mejorar de varias maneras, no dudes en hacerlo :)), esto es solo para la depuración general, 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 puedo usar así

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.


2
2018-01-07 19:22



Basado en el comentario de que estás envolviendo vsprintf, y que esto está etiquetado como C ++, sugeriría no intentar hacer esto, sino cambiar tu interfaz para usar iostreams de C ++. Ellos tienen ventajas sobre el print línea de funciones, como tipo de seguridad 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
2017-08-20 13:34



Usando el nuevo estándar C ++ 0x, puede hacer esto usando plantillas variadic o incluso convertir ese código antiguo a la sintaxis de plantilla nueva sin romper nada.


-1
2017-08-20 12:56