How to pass variable number of arguments to printf/sprintf

129,203

Solution 1

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

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

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

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

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
}
Share:
129,203
user5722
Author by

user5722

Updated on July 08, 2022

Comments

  • user5722
    user5722 almost 2 years

    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.

  • Jonathan Leffler
    Jonathan Leffler almost 15 years
    The final 'printf(dest);' is mal-formed - it needs at least a format string too.
  • Lodle
    Lodle almost 15 years
    It doesnt as the string is the format string i.e. printf("a string"); is fine
  • John Kugelman
    John Kugelman almost 15 years
    You can get away with printf(dest) up until dest happens to contain "%s" or "%d", then BOOM. Please use printf("%s", dest).
  • MickLH
    MickLH about 10 years
    Just want to come by to point out that a core dump is the best case scenario, do that in server code and hackers will have your CPU for breakfast.
  • aviggiano
    aviggiano about 8 years
    vsnprintf's second argument should be the buffer length, including the terminating null byte ('\0'). So you can use 256 in the function call instead of 255.
  • eddyq
    eddyq almost 8 years
    This is how to make an easy thing hard.
  • eddyq
    eddyq almost 8 years
    Try using "%.16383s" and that will protect the array dest from overflow. (allow for the '\0' terminator)
  • osvein
    osvein almost 7 years
    "Using functions with ellipses is not very safe." if your only safe alternative involves c++ and boost, you should explain what you mean by "not very safe", and mention that the printf functions are perfectly safe if you use the correct format specifiers.
  • Anonymouse
    Anonymouse about 5 years
    and passing magic numbers is BAD... use sizeof(buffer) instead of 256.