Skip to main content

Macros and #define

beginner14 min readLesson 61 of 148

Text substitution with rules: object macros, function-like macros, and the parenthesis trap.

Two kinds of macros

#define MAX_SCORE 100                  // object macro: a named constant
#define SQUARE(x) ((x) * (x))          // function-like macro

The preprocessor replaces text BEFORE compilation. SQUARE(a+b) becomes ((a+b) * (a+b)) โ€” the compiler never sees the name SQUARE.

The parenthesis trap

#define BAD_SQUARE(x) (x * x)
BAD_SQUARE(2 + 3)     // becomes (2 + 3 * 2 + 3) = 11 โ€” not 25!

Every parameter AND the whole expansion get parentheses. This is not style; it is correctness.

The double-evaluation trap

#define MAX(a, b) ((a) > (b) ? (a) : (b))
int i = 5;
MAX(i++, 3);    // i++ may be evaluated TWICE โ€” side effects multiply

Macros paste text; arguments with side effects are dangerous. A do-while wrapper gives statement-like macros sane semantics:

#define LOG(msg) do { fprintf(stderr, "%s\n", msg); } while (0)

#undef and scope

Macros live from their #define to the end of the file (or #undef). They do not respect C scopes โ€” a macro named SIZE will clobber any SIZE in every header included after it. Name them deliberately (or not at all: a const or static const is often the better tool).

Now practice

Macro MechanicsFunction-like macros that must survive compound arguments.3 challenges ยท ยท ~14 min