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

Tengo una clase que contiene una función de “error” que formateará algún texto. Quiero aceptar una cantidad variable de argumentos y luego formatearlos usando printf.

Ejemplo:

class MyClass { public: void Error(const char* format, ...); }; 

El método de error debe tomar los parámetros, invocar printf / sprintf para formatearlo y luego hacer algo con él. No quiero escribir todo el formato, por lo que tiene sentido intentar averiguar cómo usar el formato existente.

Malo

 void Error(const char* format, ...) { char dest[1024 * 16]; va_list argptr; va_start(argptr, format); vsprintf(dest, format, argptr); va_end(argptr); printf(dest); } 

Este código no es tan bueno. Utiliza un búfer de caracteres de tamaño fijo que puede provocar un error de desbordamiento del búfer si la cadena es patológicamente larga. El tamaño arbitrario de 1024*16 debe hacer sonar una bandera en tu cabeza. Además, la llamada printf podría tener problemas si el dest termina conteniendo códigos de formato. Mejor sería printf("%s", dest) . Pero aún mejor sería usar vprintf o vfprintf :

Bueno

 void Error(const char* format, ...) { va_list argptr; va_start(argptr, format); vfprintf(stderr, format, argptr); va_end(argptr); } 

Si desea manipular la cadena antes de mostrarla y realmente la necesita almacenada primero en un buffer, use vsnprintf lugar de vsprintf . vsnprintf evitará un error accidental de desbordamiento de búfer.

eche un vistazo a vsnprintf ya que esto hará lo que quiera http://www.cplusplus.com/reference/clibrary/cstdio/vsprintf/

primero deberá iniciar la matriz de argumentos va_list y luego llamarla.

Ejemplo de ese enlace: / * vsprintf example * /

 #include  #include  void Error (char * format, ...) { char buffer[256]; va_list args; va_start (args, format); vsnprintf (buffer, 255, format, args); //do something with the error va_end (args); } 

Usar funciones con las elipses no es muy seguro. Si el rendimiento no es crítico para la función de registro, considere usar la sobrecarga del operador como en el formato boost ::. Podrías escribir algo como esto:

 #include  #include  #include  using namespace std; class formatted_log_t { public: formatted_log_t(const char* msg ) : fmt(msg) {} ~formatted_log_t() { cout < < fmt << endl; } template  formatted_log_t& operator %(T value) { fmt % value; return *this; } protected: boost::format fmt; }; formatted_log_t log(const char* msg) { return formatted_log_t( msg ); } // use int main () { log("hello %s in %d-th time") % "world" % 10000000; return 0; } 

El siguiente ejemplo demuestra posibles errores con puntos suspensivos:

 int x = SOME_VALUE; double y = SOME_MORE_VALUE; printf( "some var = %f, other one %f", y, x ); // no errors at compile time, but error at runtime. compiler do not know types you wanted log( "some var = %f, other one %f" ) % y % x; // no errors. %f only for compatibility. you could write %1% instead. 

Debería haber leído más sobre las preguntas existentes en desbordamiento de stack.

C ++ Pasando Variable Número de argumentos es una pregunta similar. Mike F tiene la siguiente explicación:

No hay forma de llamar (por ejemplo) printf sin saber cuántos argumentos le estás pasando, a menos que quieras entrar en trucos traviesos y no portátiles.

La solución generalmente utilizada es proporcionar siempre una forma alternativa de funciones vararg, así que printf tiene vprintf que toma una va_list en lugar de …. Las … versiones son solo envoltorios alrededor de las versiones de va_list.

Esto es exactamente lo que estaba buscando. Realicé una implementación de prueba como esta:

 void Error(const char* format, ...) { char dest[1024 * 16]; va_list argptr; va_start(argptr, format); vsprintf(dest, format, argptr); va_end(argptr); printf(dest); } 

Usted está buscando funciones variadas . printf () y sprintf () son funciones variadas: pueden aceptar un número variable de argumentos.

Esto implica básicamente estos pasos:

  1. El primer parámetro debe dar alguna indicación del número de parámetros que siguen. Entonces, en printf (), el parámetro “formato” da esta indicación: si tiene 5 especificadores de formato, entonces buscará 5 argumentos más (para un total de 6 argumentos). El primer argumento podría ser un entero (por ejemplo, “mi función (3, a, b, c) “donde” 3 “significa” 3 argumentos)

  2. Luego recorra y recupere cada argumento sucesivo, usando las funciones va_start () etc.

Hay muchos tutoriales sobre cómo hacer esto: ¡buena suerte!

Ejemplo simple a continuación. Tenga en cuenta que debe pasar un buffer más grande y probar para ver si el buffer fue lo suficientemente grande o no

 void Log(LPCWSTR pFormat, ...) { va_list pArg; va_start(pArg, pFormat); char buf[1000]; int len = _vsntprintf(buf, 1000, pFormat, pArg); va_end(pArg); //do something with buf } 

Eche un vistazo al ejemplo http://www.cplusplus.com/reference/clibrary/cstdarg/va_arg/ , pasan el número de argumentos al método, pero puede omitirlo y modificar el código de manera apropiada (vea el ejemplo).