Complex expressions can be used as macro parameters, and operator-precedence problems can arise unless all occurrences of parameters have parentheses around them. There is little that can be done about the problems caused by side effects in parameters except to avoid side effects in expressions (a good idea anyway) and, when possible, to write macros that evaluate their parameters exactly once. There are times when it is impossible to write macros that act exactly like functions.
Some macros also exist as functions (e.g.,
getc
and
fgetc
).
The macro should be used in implementing the function
so that changes to the macro
will be automatically reflected in the function.
Care is needed when interchanging macros and functions since function
parameters are passed by value, while macro parameters are passed by
name substitution.
Carefree use of macros requires that they be declared carefully.
Macros should avoid using globals, since the global name may be hidden by a local declaration. Macros that change named parameters (rather than the storage they point at) or may be used as the left-hand side of an assignment should mention this in their comments. Macros that take no parameters but reference variables, are long, or are aliases for function calls should be given an empty parameter list, e.g.,
#define OFF_A() (a_global+OFFSET)
#define BORK() (zork())
#define SP3() if (b) { int x; av = f (&x); bv += x; }
Macros save function call/return overhead, but when a macro gets long, the effect of the call/return becomes negligible, so a function should be used instead.
In some cases it is appropriate to make the compiler insure that a macro is terminated with a semicolon.
if (x==3)
SP3();
else
BORK();
SP3
,
then the
else
will (silently!) become associated with the
if
in the
SP3
macro.
With the semicolon, the
else
doesn't match any
if
!
The macro
SP3
can be written safely as
#define SP3() \
do { if (b) { int x; av = f (&x); bv += x; }} while (0)
do-while
by hand is awkward and some compilers and tools
may complain that there is a constant in the
``while
''
conditional.
A macro for declaring statements may make programming easier.
#ifdef lint
static int ZERO;
#else
# define ZERO 0
#endif
#define STMT( stuff ) do { stuff } while (ZERO)
SP3
with
#define SP3() \ STMT( if (b) { int x; av = f (&x); bv += x; } )Using
STMT
will help prevent small typos from silently changing programs.
Except for type casts,
sizeof
,
and hacks such as the above,
macros should contain keywords only if the entire
macro is surrounded by braces.