Understanding C Macro Expansion: When Parameters Expand and When They Don’t
This article explains the C preprocessor's macro‑expansion rules, detailing when macro arguments are expanded, how replacement‑list macros behave, special cases involving the # and ## operators, and provides step‑by‑step examples and techniques for controlling expansion.
Macro Expansion Rules
In the C preprocessor, when a macro argument is itself a macro, its expansion follows a two‑step process: first the argument is expanded (parameter replacement), then the replacement list is processed. Symbols in the replacement list are further expanded unless they appear as operands of the stringizing operator # or the token‑pasting operator ##.
Parameter expansion timing
During macro invocation the preprocessor substitutes actual arguments for formal parameters.
If an argument is a macro, it is expanded before substitution.
Replacement‑list expansion
Each token in the replacement list is examined; macro tokens are expanded.
A macro parameter used with # or ## is not expanded.
Key rules
Parameter expansion precedes replacement‑list expansion.
After substitution, the resulting tokens are expanded again unless protected by # or ##.
Examples
Example 1 – parameter expands first
#define A 123
#define PRINT(x) printf("%d
", x)Invocation: PRINT(A); Parameter replacement: A expands to 123.
Replacement‑list expansion: 123 replaces x in the printf call, yielding
printf("%d
", 123); 123Example 2 – stringizing prevents expansion
#define A 123
#define STRINGIFY(x) #xInvocation: printf("%s\n", STRINGIFY(A)); Parameter replacement: A is not expanded because STRINGIFY uses #.
Replacement‑list expansion: The result is
printf("%s
", "A"); AExample 3 – token‑pasting prevents expansion
#define A 123
#define CONCAT(x, y) x##yInvocation: CONCAT(A, B); Parameter replacement: A is not expanded because CONCAT uses ##.
Replacement‑list expansion: Tokens A and B are concatenated, producing AB, not 123B.
ABForcing expansion before # or ##
Introduce an intermediate helper macro that performs the stringizing or concatenation after a first level of expansion:
#define STRINGIFY(x) STRINGIFY_HELPER(x)
#define STRINGIFY_HELPER(x) #x
#define STRINGCAT(x, y) STRINGCAT_HELPER(x, y)
#define STRINGCAT_HELPER(x, y) x##yThese two‑step macros ensure that arguments are fully expanded before the operators are applied.
Why two‑step macros are required
The preprocessor expands macro arguments only once unless an extra level of indirection is provided.
Direct definitions such as #define STRINGIFY(x) #x or #define CONCAT(x, y) x##y would operate on the raw tokens, ignoring any nested macro expansions.
Summary
The C preprocessor follows a predictable two‑step expansion process: macro arguments are expanded before being placed into the replacement list, and symbols in the replacement list are further expanded unless they appear as operands of # or ##. Using helper macros provides the necessary indirection to obtain the expanded value when stringizing or token‑pasting.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Liangxu Linux
Liangxu, a self‑taught IT professional now working as a Linux development engineer at a Fortune 500 multinational, shares extensive Linux knowledge—fundamentals, applications, tools, plus Git, databases, Raspberry Pi, etc. (Reply “Linux” to receive essential resources.)
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
