A macro is a name the preprocessor replaces with some text before the compiler runs. That is the entire mechanism, and every rule on this page is a consequence of it: macros do not have types, do not respect scope, do not evaluate arguments, and do not know what a function call is. They copy text.
Used carefully they are indispensable - portability switches, assertion macros that capture the line number, compile-time constants that work in array sizes. Used carelessly they produce bugs that look impossible until you expand the file.
Object-Like Macros
The simplest form defines a name that stands for a value:
Conventionally these names are UPPER_SNAKE_CASE so a reader can tell at a glance that a symbol is a macro and not a variable. That convention matters more than usual here, because macros ignore scope: a #define inside a function still applies to the rest of the file, and it will happily rewrite a variable of the same name in another function.
#undef NAME removes a definition, so a name can be redefined later without a warning about redefinition.
Function-Like Macros
Put a parameter list directly after the name - with no space before the opening parenthesis - and the macro takes arguments:
The space rule is real: #define SQUARE (x) ((x)*(x)) defines an object-like macro named SQUARE whose replacement text begins with (x). The compiler error that follows will not mention spacing.
The Parentheses Rules
There are two, and both exist because the body is pasted into an expression you cannot see when writing the macro.
Rule 1: parenthesize every parameter. Without it, an argument that is itself an expression gets torn apart by precedence:
#define SQUARE_BAD(x) x * x
SQUARE_BAD(2 + 3) /* becomes 2 + 3 * 2 + 3 == 11, not 25 */
Rule 2: parenthesize the whole body. Without it, the surrounding expression tears the result apart:
#define DOUBLE_BAD(x) (x) + (x)
10 / DOUBLE_BAD(5) /* becomes 10 / (5) + (5) == 7, not 1 */
Run both failures side by side with their fixed versions:
Both bad versions compile without a single warning and produce wrong numbers. The habit to build is mechanical: wrap each parameter, then wrap the result. ((a) > (b) ? (a) : (b)) looks noisy, and the noise is the point.
The Multiple-Evaluation Trap
Parentheses cannot save you from the second hazard. A macro pastes its argument text at every place the parameter appears, so an argument with a side effect happens more than once:
The macro expands to ((i++) > (j) ? (i++) : (j)). The comparison increments i to 6 and compares 5 with 3; the true branch increments i again to 7 and yields 6. So m is 6 and i is 7 - neither is what "the larger of i and j" should give. A function max(i++, j) would be correct, because the argument is evaluated once before the call.
The same trap catches anything with a side effect: SQUARE(rand()) calls rand() twice and multiplies two different numbers. CHECK(read_byte()) consumes two bytes.
Two defenses, in order of preference:
- Use a real function. If you need it for several types, write one per type, or use a
static inlinefunction in a header. - If it must be a macro, document loudly that arguments are evaluated more than once, and keep the call sites free of side effects.
Multi-Line Macros and do-while(0)
A macro body can span lines if each line but the last ends in a backslash. The naive version looks fine:
#define LOG_TWICE(msg) \
printf("%s\n", msg); \
printf("%s\n", msg)
And then it breaks, silently, in the one place it matters:
if (verbose)
LOG_TWICE("hello");
else
printf("quiet\n");
After substitution the if owns only the first printf, the second runs unconditionally, and the else now has no matching if - a compile error whose message points nowhere useful. Wrapping the body in plain braces is no better: the trailing ; after LOG_TWICE("hello") becomes an empty statement that terminates the if, and the else breaks again.
The idiom that works is do { ... } while (0):
do { ... } while (0) is a single statement, it runs its body exactly once, and it requires a semicolon after it - so the call site reads like an ordinary function call and behaves like one in every control-flow context. Watch the backslashes: a stray space after a backslash ends the continuation and produces a baffling error.
Predefined Macros and Assertion Patterns
The preprocessor defines several macros itself, and they are the reason some things simply cannot be functions:
__FILE__ and __LINE__ expand where they are written, so putting them inside a macro captures the caller's position. A function could not do this - inside a function they would always report the logging function's own file and line. This is exactly how the standard assert macro reports the failing expression's location.
Other useful predefined names: __DATE__, __TIME__, and __STDC_VERSION__ (for example 201710L for C17).
Two Operators Worth Knowing
Inside a macro body, # turns a parameter into a string literal ("stringizing") and ## glues tokens together ("token pasting").
SHOW(width * height) becomes printf("width * height" " = %d\n", (width * height)); - adjacent string literals are joined by the compiler, so one call prints both the expression text and its value. It is a debugging trick worth remembering.
## is rarer and mostly appears in code-generation macros: #define MAKE_VAR(n) int var_##n turns MAKE_VAR(3) into int var_3. Use it sparingly; identifiers built by the preprocessor cannot be searched for by name, which makes the code hard to navigate.
Macros vs Functions vs const
Use the weakest tool that does the job:
constvariable -const double PI = 3.14159;has a type, obeys scope, appears in the debugger, and cannot be redefined by an unrelated header. Prefer it for values used at runtime.enum-enum { MAX_USERS = 100 };gives a named integer constant that works where C demands a compile-time constant, with a type and scope. Good for integer limits.static inlinefunction - type-checked, evaluates each argument exactly once, and modern compilers inline it just as a macro would. This is the right replacement for nearly every function-like macro.- Macro - when you need
__LINE__, when the thing must work before types exist (array sizes in older code), when you are switching code with conditional compilation, or when you are generating repetitive code.
One place macros remain uncontested is array sizing, because the result must be a compile-time constant:
This one has a well-known caveat of its own: it is correct only for a genuine array. Pass a pointer - which is what an array becomes when handed to a function - and sizeof measures the pointer, giving a wrong and confidently silent answer.
Debugging a Macro
When a macro misbehaves, do not stare at it. Expand it:
gcc -E program.c | tail -30
The substituted text tells you immediately whether the problem is a missing parenthesis, a double evaluation, or a name colliding with something else. Compile with -Wall -Wextra too - GCC and clang add "in expansion of macro" notes that connect the reported error line back to the definition.
Next up: header files, where #define and #include combine to let one project span many source files without pasting the same declarations twice.
Frequently Asked Questions
What is a macro in C?
A named piece of text that the preprocessor substitutes into your source before compilation. #define MAX 100 makes every later MAX become 100; #define SQUARE(x) ((x) * (x)) takes arguments and substitutes them into a pattern. Macros have no types and obey no scope rules - they are text replacement.
Why do C macros need so many parentheses?
Because the body is pasted into surrounding code and then parsed as a whole. #define SQUARE(x) x * x turns SQUARE(2 + 3) into 2 + 3 * 2 + 3, which is 11 rather than 25. Wrapping every argument and the entire body - ((x) * (x)) - makes the substituted text group the way you intended regardless of what is around it.
What is the difference between a macro and a function in C?
A function is compiled once, type-checked, and evaluates each argument exactly once. A macro is pasted at every use, checks nothing, and may evaluate an argument several times - so MAX(i++, j) can increment i twice. Prefer functions (and const/enum for constants); use macros for things functions cannot do, such as capturing __LINE__ or generating code.
Why is a multi-line macro wrapped in do { ... } while (0)?
So it behaves like a single statement. A bare { ... } body breaks when followed by a semicolon inside an if/else (the semicolon ends the if early), and a plain sequence of statements breaks in an unbraced if. do { ... } while (0) is one statement that accepts a trailing semicolon and runs its body exactly once.