Macros

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();
If the semicolon is omitted after the call to 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)
Writing out the enclosing 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)
Declare 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.