28

Possible Duplicate:
C/C++: Passing variable number of arguments around

I'm currently using the following macro declared on my C file.

#define COMMON_Print(...) printf (__VA_ARGS__)

Now that call works just fine, but turns out that I need to be able to create a C function that looks something like this:

void COMMON_Print(...)
{    
    printf (__VA_ARGS__);
}

So that function doesn't work, I get an error

"Error : undefined identifier __VA_ARGS__"

The complexity of my project requires to have a function since it's an interface... So how can I get the parameters ... and pass them to the printf function? Or better what am I doing wrong?

Thanks!

Community
  • 1
  • 1
Jona
  • 13,325
  • 15
  • 86
  • 129
  • 1
    See this http://stackoverflow.com/questions/205529/c-c-passing-variable-number-of-arguments-around – Kos Dec 02 '10 at 20:19

4 Answers4

49

Each of the ?printf functions has a corresponding v?printf function which does the same thing but takes a va_list, a variable argument list.

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

void COMMON_Print(char *format, ...)
{
    va_list args;

    va_start(args, format);
    vprintf(format, args);
    va_end(args);
}

Side note: Notice that va_start takes the name of the last argument before the ... as a parameter. va_start is a macro which does some stack-based magic to retrieve the variable arguments and it needs the address of the last fixed argument to do this.

As a consequence of this, there has to be at least one fixed argument so you can pass it to va_start. This is why I added the format argument instead of sticking with the simpler COMMON_Print(...) declaration.

See: http://www.cplusplus.com/reference/clibrary/cstdio/vprintf/

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
  • 1
    If you use macros, you need no preceding arg. Consider this example: `#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__))` This obviously is very convenient from a usage viewpoint. – Engineer Jul 28 '15 at 11:39
24

__VA_ARGS__ is only for macros; variadic functions are rather different. You need to use va_start, va_arg and va_end from stdarg.h to handle them.

First, your function needs at least one named parameter, e.g.:

void COMMON_Print(const char* fmt, ...)

Then you can define a va_list and use va_start to set it:

va_list args;
va_start(args, fmt);
// your code here
va_end(args);

Now you can use args to access the arguments; calling va_arg(args, TYPE) will return the next variadic argument, so you can just keep calling that until you've read all the arguments.

If you're just trying to call printf, there's a printf variant called vprintf that takes the va_list directly:

vprintf(fmt, args);

There is no easy way to call one variadic function from another; you need something like vprintf that takes the whole va_list

Michael Mrozek
  • 169,610
  • 28
  • 168
  • 175
  • 'va_arg(args, TYPE)' will return NULL only if NULL was passed by the caller. There is no default end condition for va_arg. You must either pass a sentinel value or know the exact number of parameters, passed by a parameter or by counting the number of % in a printf format string. – Patrick Schlüter Dec 02 '10 at 21:05
  • @tristopia Oh, right; I'm in the habit of passing NULL at the end when necessary. Fixed – Michael Mrozek Dec 02 '10 at 21:08
8

__VA_ARGS__ is for macros only.

Chaining the variable number of argument to another function can't be done directly. Instead you have to pass a va_list , and the function you're calling have to take a va_list. Luckily there's a variation of printf that does this, your function have to be written this way:

void COMMON_Print(char *format,...)
{    
  va_list args;
  va_start(args,format);
  vprintf(format,args);
  va_end(args);
}
nos
  • 223,662
  • 58
  • 417
  • 506
  • 1
    Thanks a lot for your response! It actually works! But there are some formatting issues going on that I need to resolve on my end I believe. FYI, I'm working on an embedded device. – Jona Dec 02 '10 at 20:32
  • What is vaprintf ? Or is it just a typo ? – Vincent Fourmond Dec 01 '15 at 14:42
  • There are two errors in this code sample. The first call should be to `va_start` and not `va_begin` and the second call to `vprintf` not `vsprintf`. – Björn Lindqvist Oct 19 '21 at 10:32
4

What you are looking for is the Ellipsis operator.

Dima
  • 38,860
  • 14
  • 75
  • 115