How to pass variable number of arguments to printf/sprintf

C++CPrintfVariadic Functions

C++ Problem Overview


I have a class that holds an "error" function that will format some text. I want to accept a variable number of arguments and then format them using printf.

Example:

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

The Error method should take in the parameters, call printf/sprintf to format it and then do something with it. I don't want to write all the formatting myself so it makes sense to try and figure out how to use the existing formatting.

C++ Solutions


Solution 1 - C++

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

If you want to manipulate the string before you display it and really do need it stored in a buffer first, use vsnprintf instead of vsprintf. vsnprintf will prevent an accidental buffer overflow error.

Solution 2 - C++

have a look at vsnprintf as this will do what ya want http://www.cplusplus.com/reference/clibrary/cstdio/vsprintf/

you will have to init the va_list arg array first, then call it.

Example from that link: /* vsprintf example */

#include <stdio.h>
#include <stdarg.h>

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);
}

Solution 3 - C++

I should have read more on existing questions in stack overflow.

C++ Passing Variable Number of Arguments is a similar question. Mike F has the following explanation:

> There's no way of calling (eg) printf > without knowing how many arguments > you're passing to it, unless you want > to get into naughty and non-portable > tricks. > > The generally used solution is to > always provide an alternate form of > vararg functions, so printf has > vprintf which takes a va_list in place > of the .... The ... versions are just > wrappers around the va_list versions.

This is exactly what I was looking for. I performed a test implementation like this:

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);
}

Solution 4 - C++

You are looking for variadic functions. printf() and sprintf() are variadic functions - they can accept a variable number of arguments.

This entails basically these steps:

  1. The first parameter must give some indication of the number of parameters that follow. So in printf(), the "format" parameter gives this indication - if you have 5 format specifiers, then it will look for 5 more arguments (for a total of 6 arguments.) The first argument could be an integer (eg "myfunction(3, a, b, c)" where "3" signifies "3 arguments)

  2. Then loop through and retrieve each successive argument, using the va_start() etc. functions.

There are plenty of tutorials on how to do this - good luck!

Solution 5 - C++

Simple example below. Note you should pass in a larger buffer, and test to see if the buffer was large enough or not

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
}

Solution 6 - C++

Using functions with the ellipses is not very safe. If performance is not critical for log function consider using operator overloading as in boost::format. You could write something like this:

#include <sstream>
#include <boost/format.hpp>
#include <iostream>
using namespace std;




class formatted_log_t {
public:
formatted_log_t(const char* msg ) : fmt(msg) {}
~formatted_log_t() { cout << fmt << endl; }



template &lt;typename T>
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;
}

// use int main () { log("hello %s in %d-th time") % "world" % 10000000; return 0; }

The following sample demonstrates possible errors with ellipses:

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.

Solution 7 - C++

Have a look at the example http://www.cplusplus.com/reference/clibrary/cstdarg/va_arg/, they pass the number of arguments to the method but you can ommit that and modify the code appropriately (see the example).

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser5722View Question on Stackoverflow
Solution 1 - C++John KugelmanView Answer on Stackoverflow
Solution 2 - C++LodleView Answer on Stackoverflow
Solution 3 - C++user5722View Answer on Stackoverflow
Solution 4 - C++poundifdefView Answer on Stackoverflow
Solution 5 - C++DougNView Answer on Stackoverflow
Solution 6 - C++Kirill V. LyadvinskyView Answer on Stackoverflow
Solution 7 - C++stefanBView Answer on Stackoverflow