When preprocessed with the GNU compiler, it prints, as probably desired:
P1 = foo | P2 = bar | P3 = baz
However, when preprocessed with Microsoft's compiler, it emits the warning C4003: not enough arguments for function-like macro invocation 'MACRO_WITH_3_PARAMS' and prints:
P1 = foo, bar, baz | P2 = | P3 =
That is: Microsoft's preprocessor expands everything into one parameter of MACRO_WITH_3_PARAMS.
In order for both preprocessors to emit the text, another macro needs to be defined that just passes on what it receives. This macro (PASS_ON) is then applied on a macro name (MACRO_WITH_3_PARAMS) so that the macro name dos not get expanded and a second time with the parameters:
With this «solution», both preprocessors now emit:
P1 = foo | P2 = bar | P3 = baz
Simple example
The following simple example uses __VA_ARGS__ to create a macro that takes a variable number of arguments with the three dots. The variable number of arguments that are represented by the dots are passed to __VA_ARGS__:
#include <stdio.h>
#define TQ84_PRINTF(FORMAT, ...) printf("tq84: " FORMAT "\n", __VA_ARGS__)
int main() {
TQ84_PRINTF("%d", 42);
TQ84_PRINTF("%s, %s", "Hello", "world");
TQ84_PRINTF("%d %f %s", 99, 3.14, "An int and a float");
}
The following file was preprocessed with the Visual C compiler (cl /EP basic) and the GNU compiler (gcc -x c -E-P basic) to demonstrate a difference between their preprocessors.
// gcc | cl
// --------------------------------- // ----------- + --------------------------------
#define A(...) __VA_ARGS__ // |
A // A | A
A() // |
A(1) // 1 | 1
A(1,2) // 1,2 | 1,2
// |
#define B(...) A( __VA_ARGS__) // |
B // B | B
B() // |
B(one) // one | one
B(one,two) // one,two | one,two
// |
#define C(x, ...) A(x,__VA_ARGS__) // |
C // C | C
C() // , | , basic(17): warning C4003: not enough arguments for function-like macro invocation 'C'
C(i) // i, | i,
C(ii,iii) // ii,iii | ii,iii
C(iv,v,vi) // iv,v,vi | iv,v,vi
// |
#define D(x, ...) Q(x,__VA_ARGS__) // |
D // D | D
D() // Q(,) | Q( ) basic(24): warning C4003: not enough arguments for function-like macro invocation 'D'
D(a) // Q(a,) | Q(a )
D(b,c) // Q(b,c) | Q(b,c)
D(d,e,f) // Q(d,e,f) | Q(d,e,f)