Sunday, December 18, 2005

MACRO

What does the message ``warning: macro replacement within a string literal'' mean?

Some pre-ANSI compilers/preprocessors interpreted macro definitions like

#define TRACE(var, fmt) printf("TRACE: var = fmt\n", var)

such that invocations like

TRACE(i, %d);


were expanded as

printf("TRACE: i = %d\n", i);


In other words, macro parameters were expanded even inside string literals and character constants.

Macro expansion is not defined in this way by K&R or by Standard C. When you do want to turn macro arguments into strings, you can use the new # preprocessing operator, along with string literal concatenation (another new ANSI feature):

#define TRACE(var, fmt) printf("TRACE: " #var " = " #fmt "\n", var)


What's the best way to write a multi-statement macro?

ANSWER:
#define MACRO(arg1, arg2) do { \
/* declarations */ \
stmt1; \
stmt2; \
/* ... */ \
} while(0) /* (no trailing ; ) */


How can I write a macro which takes a variable number of arguments?
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.

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 to use different macros (DEBUG1, DEBUG2, etc.) depending on the number of arguments, to play games with commas:

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

DEBUG("i = %d" _ i)

No comments: