π Click the blue text "Linux Armory" at the top, and select "Add to Favorites" in the upper right corner
Don’t miss out on great articles, see valuable content first
π FollowLinux Armory, to receive hardcore Linux learning materials and code
unset1. Macro Expansion Rulesunsetunset
In the C language preprocessor, if a macro parameter itself is a macro, the timing of its expansion follows certain rules. Specifically, the timing of the macro parameter’s expansion depends on its position and usage in the macro definition. Here are the detailed rules and explanations:
Timing of Macro Parameter Expansion
When a macro is called, the preprocessor processes the macro parameters according to the following steps:
Parameter Replacement
- During the macro call, the preprocessor replaces the macro parameters with actual arguments.
- If the macro parameter itself is a macro, the preprocessor first expands this macro parameter before performing the replacement.
Macro Expansion in Replacement List
- In the replacement list, the preprocessor processes each symbol one by one. If the symbol is a macro, the preprocessor further expands this macro.
- However, if the symbol is a macro parameter and this macro parameter is used as a parameter for the
<span>#</span>
or<span>##</span>
operators in the replacement list, this macro parameter will not be expanded.
Specific Rules
- Parameter Expansion Takes Precedence Over Replacement List Expansion: Macro parameters are expanded before being replaced in the replacement list.
- Macro Expansion in Replacement List: Symbols in the replacement list (including expanded parameters) will be further expanded unless they are used as parameters for the
<span>#</span>
or<span>##</span>
operators.
Examples
Example 1: Parameter Expansion Takes Precedence
Assume we have the following macro definition:
#define A 123
#define PRINT(x) printf("%d\n", x)
Calling the macro:
PRINT(A);
Expansion process:
-
Parameter Replacement:
<span>A</span>
is a macro, the preprocessor first expands<span>A</span>
, resulting in<span>123</span>
. -
Replacement List Expansion: Replace
<span>123</span>
in the<span>PRINT</span>
replacement list, resulting in:printf("%d\n", 123);
Final output:
123
Example 2: Parameter Not Expanded (<span>#</span>
Operator)
Assume we have the following macro definition:
#define A 123
#define STRINGIFY(x) #x
Calling the macro:
printf("%s\n", STRINGIFY(A));
Expansion process:
-
Parameter Replacement:
<span>A</span>
is a macro, but since<span>STRINGIFY</span>
uses the<span>#</span>
operator in its replacement list,<span>A</span>
will not be expanded. -
Replacement List Expansion: Replace
<span>A</span>
in the<span>STRINGIFY</span>
replacement list, resulting in:printf("%s\n", "A");
Final output:
A
Example 3: Parameter Not Expanded (<span>##</span>
Operator)
Assume we have the following macro definition:
#define A 123
#define CONCAT(x, y) x##y
Calling the macro:
CONCAT(A, B);
Expansion process:
-
Parameter Replacement:
<span>A</span>
is a macro, but since<span>CONCAT</span>
uses the<span>##</span>
operator in its replacement list,<span>A</span>
will not be expanded. -
Replacement List Expansion: Replace
<span>A</span>
and<span>B</span>
in the<span>CONCAT</span>
replacement list, resulting in:AB
Final result:<span>AB</span>
is a symbol, not <span>123B</span>
.
4. Rules
- Parameter Expansion Takes Precedence: Macro parameters are expanded before being replaced in the replacement list.
- Macro Expansion in Replacement List: Symbols in the replacement list will be further expanded unless they are used as parameters for the
<span>#</span>
or<span>##</span>
operators. - Special Cases: If a macro parameter is used as a parameter for the
<span>#</span>
or<span>##</span>
operators in the replacement list, this macro parameter will not be expanded.
unsetunset2. Handling Non-Expanded Macro Parametersunsetunset
#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##y
These rules ensure that the macro expansion process is predictable while also providing a flexible way to control macro behavior.
This code defines two macros <span>STRINGIFY</span>
and <span>STRINGIFY_HELPER</span>
, as well as <span>STRINGCAT</span>
and <span>STRINGCAT_HELPER</span>
. The reason for needing two macros to achieve functionality instead of using a single macro directly is due to the working mechanism of the C preprocessor.
Explanation of Reasons
-
Preprocessor Expansion Rules In the C preprocessor, macro parameters are not immediately replaced with actual values during the first expansion; they retain their original form. Only through indirect expansion (i.e., via another macro call) can the actual values of the parameters be correctly resolved.
-
Specific Scenario Analysis
- For
<span>STRINGIFY(x)</span>
, if defined directly as<span>#x</span>
, it cannot correctly handle macros with parameters or complex expressions. By using<span>STRINGIFY_HELPER(x)</span>
for indirect calls, it ensures that parameters are correctly expanded before being stringified. - Similarly, for
<span>STRINGCAT(x, y)</span>
, if defined directly as<span>x##y</span>
, it cannot correctly concatenate macros with parameters or complex expressions. By using<span>STRINGCAT_HELPER(x, y)</span>
for indirect calls, it ensures that parameters are correctly expanded before concatenation.
Example Comparison Assume we have the following code:
#define FOO 123
#define STRINGIFY(x) #x
#define STRINGCAT(x, y) x##y
const char* str = STRINGIFY(FOO); // Result is "FOO" instead of "123"
int value = STRINGCAT(FOO, 456); // Result is FOO456 instead of 123456
If using indirect macros:
#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##y
const char* str = STRINGIFY(FOO); // Result is "123"
int value = STRINGCAT(FOO, 456); // Result is 123456
Through indirect macro calls, parameters are correctly expanded, achieving the expected functionality.
unsetunsetConclusionunsetunset
The reason for defining two macros is to utilize the two-step expansion mechanism of the C preprocessor, ensuring that macro parameters can be correctly resolved and processed. If only one macro were used, it would not be able to correctly handle complex macro parameters or expressions.
ββ Recommended Articles ββ
π Detailed Method for Creating Library Files in Linux
π Summary of Most Common Command Usages in Linux (Selected)
π Step-by-Step Guide to Writing Linux Thread Pools
π Summary of Common Methods in Linux Shell Programming
π Essence of C++ Basic Knowledge
ββ Recommended Collections ββ
π Collection of C Language Introductory Tutorials
π Collection of Common Software Tools
π Collection of Linux Knowledge
π Collection of Detailed Linux Libraries
π Linux Application Programming Collection
For learning and communication, pleaseadd Assistant WeChat to join a high-quality learning group
π Learn from others’ strengths to make up for your own shortcomings π
Please clickβγTechnical Learning Groupγ
β
FollowLinux Armory, reply in the chat interface withγ1024γ to get all Linux materials and code.
β
Technical work requires step-by-step accumulation, building up to significant resultsγDo not regret wasting time, do not feel ashamed of being mediocreγ
Make a little progress every day, support the author, remember to like and share! Add the assistant’s WeChat to receive numerous classic open-source project source codes, read anytime, anywhere, thereβs always one that can help you!
Support the author, please extend your little hand to wealth
Share, collectπππππLike, see
Support quality content with action!