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.
There is an argument counting trick that you can use.
Here is one standard-compliant way to implement the second BAR()
example in jwd's question:
#include <stdio.h>
#define BAR(...) printf(FIRST(__VA_ARGS__) "\n" REST(__VA_ARGS__))
/* expands to the first argument */
#define FIRST(...) FIRST_HELPER(__VA_ARGS__, throwaway)
#define FIRST_HELPER(first, ...) first
/*
* if there's only one argument, expands to nothing. if there is more
* than one argument, expands to a comma followed by everything but
* the first argument. only supports up to 9 arguments but can be
* trivially expanded.
*/
#define REST(...) REST_HELPER(NUM(__VA_ARGS__), __VA_ARGS__)
#define REST_HELPER(qty, ...) REST_HELPER2(qty, __VA_ARGS__)
#define REST_HELPER2(qty, ...) REST_HELPER_##qty(__VA_ARGS__)
#define REST_HELPER_ONE(first)
#define REST_HELPER_TWOORMORE(first, ...) , __VA_ARGS__
#define NUM(...) \
SELECT_10TH(__VA_ARGS__, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE,\
TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, ONE, throwaway)
#define SELECT_10TH(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, ...) a10
int
main(int argc, char *argv[])
{
BAR("first test");
BAR("second test: %s", "a string");
return 0;
}
This same trick is used to:
- count the number of arguments
- expand differently depending on the number of arguments
- append to
__VA_ARGS__
Explanation
The strategy is to separate __VA_ARGS__
into the first argument and the rest (if any). This makes it possible to insert stuff after the first argument but before the second (if present).
FIRST()
This macro simply expands to the first argument, discarding the rest.
The implementation is straightforward. The throwaway
argument ensures that FIRST_HELPER()
gets two arguments, which is required because the ...
needs at least one. With one argument, it expands as follows:
FIRST(firstarg)
FIRST_HELPER(firstarg, throwaway)
firstarg
With two or more, it expands as follows:
FIRST(firstarg, secondarg, thirdarg)
FIRST_HELPER(firstarg, secondarg, thirdarg, throwaway)
firstarg
REST()
This macro expands to everything but the first argument (including the comma after the first argument, if there is more than one argument).
The implementation of this macro is far more complicated. The general strategy is to count the number of arguments (one or more than one) and then expand to either REST_HELPER_ONE()
(if only one argument given) or REST_HELPER_TWOORMORE()
(if two or more arguments given). REST_HELPER_ONE()
simply expands to nothing -- there are no arguments after the first, so the remaining arguments is the empty set. REST_HELPER_TWOORMORE()
is also straightforward -- it expands to a comma followed by everything except the first argument.
The arguments are counted using the NUM()
macro. This macro expands to ONE
if only one argument is given, TWOORMORE
if between two and nine arguments are given, and breaks if 10 or more arguments are given (because it expands to the 10th argument).
The NUM()
macro uses the SELECT_10TH()
macro to determine the number of arguments. As its name implies, SELECT_10TH()
simply expands to its 10th argument. Because of the ellipsis, SELECT_10TH()
needs to be passed at least 11 arguments (the standard says that there must be at least one argument for the ellipsis). This is why NUM()
passes throwaway
as the last argument (without it, passing one argument to NUM()
would result in only 10 arguments being passed to SELECT_10TH()
, which would violate the standard).
Selection of either REST_HELPER_ONE()
or REST_HELPER_TWOORMORE()
is done by concatenating REST_HELPER_
with the expansion of NUM(__VA_ARGS__)
in REST_HELPER2()
. Note that the purpose of REST_HELPER()
is to ensure that NUM(__VA_ARGS__)
is fully expanded before being concatenated with REST_HELPER_
.
Expansion with one argument goes as follows:
REST(firstarg)
REST_HELPER(NUM(firstarg), firstarg)
REST_HELPER2(SELECT_10TH(firstarg, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, ONE, throwaway), firstarg)
REST_HELPER2(ONE, firstarg)
REST_HELPER_ONE(firstarg)
- (empty)
Expansion with two or more arguments goes as follows:
REST(firstarg, secondarg, thirdarg)
REST_HELPER(NUM(firstarg, secondarg, thirdarg), firstarg, secondarg, thirdarg)
REST_HELPER2(SELECT_10TH(firstarg, secondarg, thirdarg, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, ONE, throwaway), firstarg, secondarg, thirdarg)
REST_HELPER2(TWOORMORE, firstarg, secondarg, thirdarg)
REST_HELPER_TWOORMORE(firstarg, secondarg, thirdarg)
, secondarg, thirdarg
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.