How can I write a macro which takes a variable number of arguments ....

Q

How can I write a macro which takes a variable number of arguments, or use the preprocessor to ``turn off'' a function call with a variable number of arguments?

✍: Guest

A

One popular trick is to define and invoke the macro with a single, parenthesized ``argument'' which in the macro expansion becomes the entire argument list, parentheses and all, for a function such as printf:
#define DEBUG(args) (printf("DEBUG: "), printf args)
if(n != 0) DEBUG(("n is %d\n", n));
The obvious disadvantage is that the caller must always remember to use the extra parentheses. Another problem is that the macro expansion cannot insert any additional arguments (that is, DEBUG() couldn't expand to something like fprintf(debugfd, ...)).
gcc has an extension which allows a function-like macro to accept a variable number of arguments, but it's not standard. Other possible solutions are:
* Use different macros (DEBUG1, DEBUG2, etc.) depending on the number of arguments.
* Play games with commas:

#define DEBUG(args) (printf("DEBUG: "), printf(args))
#define _ ,

DEBUG("i = %d" _ i);
* Play horrendous games with mismatched parentheses:
#define DEBUG fprintf(stderr,
DEBUG "%d", x);
(These all require care on the part of the user, and all of them are rather ugly.)
C99 introduces formal support for function-like macros with variable-length argument lists. The notation ... can appear at the end of the macro ``prototype'' (just as it does for varargs functions), and the pseudomacro __VA_ARGS__ in the macro definition is replaced by the variable arguments during invocation.
Finally, you can always use a bona-fide function, which can take a variable number of arguments in a well-defined way. (If you needed a macro replacement, try using a function plus a non-function-like macro, e.g. #define printf myprintf .)
When you want to turn the debugging printouts off, you can either use a different version of your debug macro:
#define DEBUG(args) /* empty */
or, if you're using real function calls, use still more preprocessor tricks to remove the function name but not the arguments, such as
#define DEBUG (void)
or
#define DEBUG if(1) {} else printf
or
#define DEBUG 1 ? 0 : (void)

(These tricks are predicated on the assumption that a good optimizer will remove any ``dead'' printf calls or degenerate cast-to-void parenthesized comma expressions.)

2016-01-19, 596👍, 0💬