...) \ // realdbgprintf (, , cformat, __VA_ARGS__) // // The reason is that // // dbgprintf("Hallo") // // gets expanded to // // realdbgprintf (, , "Hallo", ) // // where the comma before the closing brace will result in a syntax error. // // GNU C++ supports a non-portable extension which solves this. // // #define dbgprintf(cformat, ...) \ // realdbgprintf (, , cformat, ##__VA_ARGS__) // // C++20 eventually supports the following syntax. // // #define dbgprintf(cformat, ...) \ // realdbgprintf (, , cformat __VA_OPT__(,) __VA_ARGS__) // // By using the 'cformat' string as part of the variadic arguments we can // circumvent the abovementioned incompatibilities. This is tricky but // portable. #define dbgprintf(...) realdbgprintf (, , __VA_ARGS__) could then be called as dbgprintf ("Hello, world"); which expands to realdbgprintf (, , "Hello, world"); Another example is dbgprintf("%d + %d = %d", 2, 2, 5); which expands to realdbgprintf(, , "%d + %d = %d", 2, 2, 5); Without variadic macros, writing wrappers to printf is not directly possible. The standard workaround is to use the stdargs functionality of C/C++, and have the function call vprintf instead. Trailing comma There is a portability issue with generating a trailing comma with empty args for variadic macros in C99. Some compilers (e.g., Visual Studio when not using the new standard-conformant preprocessor) will silently eliminate the trailing comma. Other compilers (e.g.: GCC) support putting in front of . # define MYLOG(FormatLiteral, ...) fprintf (stderr, "%s(%u): " FormatLiteral "\n", , , __VA_ARGS__) The following application works MYLOG("Too many balloons %u", 42); which expands to fprintf (stderr, "%s(%u): " "Too many balloons %u" "\n", , , 42); which is equivalent to fprintf (stderr, "%s(%u): Too many balloons %u\n", , , 42); But look at this application: MYLOG("Attention!"); which expands to fprintf (stderr, "%s(%u): " "Attention!" "\n", , , ); which generates a syntax error with GCC. GCC supports the following (non-portable) extension: # define MYLOG(FormatLiteral, ...) fprintf (stderr, "%s(%u): " FormatLiteral "\n", , , ##__VA_ARGS__) which removes the trailing comma when is empty. C23 solves this problem by introducing __VA_OPT__ like C++. Alternatives Before the existence of variable-arguments in C99, it was quite common to use doubly nested parentheses to exploit the variable number of arguments that could be supplied to the function: #define dbgprintf(x) realdbgprintf x could then be called as: dbgprintf (("Hello, world %d", 27)); which expands to: realdbgprintf ("Hello, world