cc99c-preprocessorvariadic-macros

Standard alternative to GCC's ##__VA_ARGS__ trick?


There is a well-known problem with empty args for variadic macros in C99.

example:

#define FOO(...)       printf(__VA_ARGS__)
#define BAR(fmt, ...)  printf(fmt, __VA_ARGS__)

FOO("this works fine");
BAR("this breaks!");

The use of BAR() above is indeed incorrect according to the C99 standard, since it will expand to:

printf("this breaks!",);

Note the trailing comma - not workable.

Some compilers (eg: Visual Studio 2010) will quietly get rid of that trailing comma for you. Other compilers (eg: GCC) support putting ## in front of __VA_ARGS__, like so:

#define BAR(fmt, ...)  printf(fmt, ##__VA_ARGS__)

But is there a standards-compliant way to get this behavior? Perhaps using multiple macros?

Right now, the ## version seems fairly well-supported (at least on my platforms), but I'd really rather use a standards-compliant solution.

Pre-emptive: I know I could just write a small function. I'm trying to do this using macros.

Edit: Here is an example (though simple) of why I would want to use BAR():

#define BAR(fmt, ...)  printf(fmt "\n", ##__VA_ARGS__)

BAR("here is a log message");
BAR("here is a log message with a param: %d", 42);

This automatically adds a newline to my BAR() logging statements, assuming fmt is always a double-quoted C-string. It does NOT print the newline as a separate printf(), which is advantageous if the logging is line-buffered and coming from multiple sources asynchronously.


Solution

  • It is possible to avoid the use of GCC's ,##__VA_ARGS__ extension if you are willing to accept some hardcoded upper limit on the number of arguments you can pass to your variadic macro, as described in Richard Hansen's answer to this question. If you do not want to have any such limit, however, to the best of my knowledge it is not possible using only C99-specified preprocessor features; you must use some extension to the language. clang and icc have adopted this GCC extension, but MSVC has not.

    Back in 2001 I wrote up the GCC extension for standardization (and the related extension that lets you use a name other than __VA_ARGS__ for the rest-parameter) in document N976, but that received no response whatsoever from the committee; I don't even know if anyone read it. In 2016 it was proposed again in N2023, and I encourage anyone who knows how that proposal is going to let us know in the comments.