liveBook · Manning

Macro

As explained in Modern C

A define directive is a C preprocessor directive that defines a macro and its replacement text.

A name for replacement text

`#define M_PI 3.14159265358979323846` makes later uses of `M_PI` expand to the stated double constant. This is textual replacement, not a declaration of a typed object. The directive begins with `#` as the first non-blank character on its line, followed by `define`, the name, replacement text, and a terminating newline. section 5.6.3 section 5.6

Macros can name initialization constants of types for which C does not provide a corresponding named constant mechanism. A replacement counts as a compile-time constant only when composed of literals of base types. Use all-capital macro names so they stand out from surrounding code. TAKEAWAY: a macro supplies source text, not a general-purpose constant declaration. section 5.6.3 section 5.6

A function-like macro adds an identifier parameter list. In `BYTECOPY(T, S)`, the replacement uses `T` and `S` in a call involving `memcpy` and `MINSIZE`. At a call, commas outside nested parentheses separate arguments. Arguments undergo macro expansion, their text replaces the parameters, and the resulting text is expanded again. Expansion temporarily disables the macro being expanded, preventing infinite recursion. section 16.1

#define MINSIZE(X, Y) (sizeof(X)<sizeof(Y) ? sizeof(X) :sizeof(Y))


!@%STYLE%@!
{"css":"{\"css\": \"font-weight: bold;\"}","target":"[[{\"line\":0,\"ch\":0},{\"line\":0,\"ch\":7}],[{\"line\":0,\"ch\":23},{\"line\":0,\"ch\":29}],[{\"line\":0,\"ch\":23},{\"line\":0,\"ch\":29}],[{\"line\":0,\"ch\":23},{\"line\":0,\"ch\":29}],[{\"line\":0,\"ch\":23},{\"line\":0,\"ch\":29}]]"}
!@%STYLE%@!

Inspect how `MINSIZE(X, Y)` places its parameters inside repeated `sizeof` expressions. The replacement is an expression; it does not call a function named `MINSIZE`. section 16.0

Function-like macros need more care than functions. Parenthesize arguments in replacement text, avoid evaluating an argument more than once, and avoid hidden control-flow effects. The `square_macro(X)` example uses `X` twice: passing `count()` therefore calls it twice. The inline `square_unsigned` function is the safer comparison for that operation. Macros remain useful when a simple interface must do work a function cannot, such as providing a type-generic interface. section 16.1 section 16.0

1   if (a) if (x) return -1;
2   else puts("a is 0!");


!@%STYLE%@!
{"css":"{\"css\": \"font-weight: bold;\"}","target":"[[{\"line\":0,\"ch\":0},{\"line\":0,\"ch\":1}],[{\"line\":0,\"ch\":4},{\"line\":0,\"ch\":6}],[{\"line\":0,\"ch\":18},{\"line\":0,\"ch\":24}],[{\"line\":1,\"ch\":0},{\"line\":1,\"ch\":1}],[{\"line\":1,\"ch\":4},{\"line\":1,\"ch\":8}],[{\"line\":1,\"ch\":9},{\"line\":1,\"ch\":13}]]"}
!@%STYLE%@!

After `ERRORCHECK(x)` expands inside `if (a)`, its hidden `if (x)` takes the following `else`. The visible layout suggests a different association: the dangling-else problem. section 10.2.1

TAKEAWAY: a macro must not change control flow surprisingly. If it can return, make that possibility clear in its name. A `do { ... } while (false)` wrapper can make a multi-statement replacement behave as one statement in an `if`/`else`, but this technique should not be abused. For platform checks, preprocessor conditions can evaluate macros and integer literals; an unknown identifier in such a condition evaluates to zero, and `#error` can stop compilation when a required feature is absent. section 10.2.1 section 8.1.5

How Modern C covers it

How deep it goes
Works through directive syntax, argument-expansion steps, repeated evaluation, and dangling-else behavior.
Examples
Uses a double-constant definition, minimum-size and byte-copy replacements, a counter-based squaring comparison, and a dangling-else expansion.
What it assumes
Assumes familiarity with C expressions, function calls, and `if`/`else`; defines macro replacement and parameter expansion explicitly.
What you can do after
Build it from scratch with `#define`, trace argument replacement, and avoid repeated evaluation or surprising control flow.
How it connects
Connects macros to named constants, inline functions, type-generic interfaces, conditional compilation, and control flow.

Also explained in

Compare how 9 books explain macro →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Modern C. The section links point to the parts of the book it draws on.