Keywords: C Preprocessor | Macro Definition | String Concatenation | Token Pasting | ## Operator
Abstract: This article provides an in-depth exploration of two primary methods for string concatenation in C/C++ preprocessor: direct string literal concatenation and macro token pasting operations. Through detailed analysis of the ## operator's working principles and usage scenarios, combined with code examples demonstrating how to avoid common pitfalls, it introduces advanced techniques for macro argument expansion and stringification, helping developers write more robust preprocessing code.
Fundamental Principles of Macro String Concatenation
In C/C++ preprocessing, string concatenation is a common requirement. According to the best answer in the Q&A data, when directly concatenating two string literals, the simplest approach is to separate them with spaces:
#define STR1 "s"
#define STR2 "1"
#define STR3 STR1 STR2
The principle behind this method lies in the C language specification, which states that adjacent string literals are automatically concatenated into a single string during the compilation phase. Therefore, STR3 expands to "s" "1" after preprocessing, ultimately equivalent to "s1" at compile time.
Limitations and Proper Usage of Token Pasting Operator ##
Although the ## operator is specifically designed for token pasting, as shown in the second answer of the Q&A data, directly applying it to string literals causes errors:
#define PPCAT_NX(A, B) A ## B
PPCAT_NX("s", "1") // Error: does not yield a valid preprocessing token
This occurs because "s" and "1" are complete preprocessing tokens themselves, and pasting them cannot form a new valid token. The reference article further explains the correct application scenarios for the ## operator: primarily for concatenating identifiers and numbers.
Advanced Techniques for Macro Argument Expansion and Stringification
For more complex scenarios, the Q&A data provides a comprehensive macro definition scheme:
#define PPCAT_NX(A, B) A ## B
#define PPCAT(A, B) PPCAT_NX(A, B)
#define STRINGIZE_NX(A) #A
#define STRINGIZE(A) STRINGIZE_NX(A)
This layered design allows control over the timing of macro argument expansion. For example:
#define T1 s
#define T2 1
STRINGIZE(PPCAT(T1, T2)) // Expands to "s1"
In contrast, STRINGIZE(PPCAT_NX(T1, T2)) generates "T1T2" because PPCAT_NX does not expand macro arguments.
Practical Application Examples
The command table case from the reference article demonstrates the practical value of macro concatenation:
#define COMMAND(NAME) { #NAME, NAME ## _command }
struct command commands[] = {
COMMAND(quit),
COMMAND(help),
// ...
};
This approach avoids duplicating command names, enhancing code maintainability.
Summary and Best Practices
For simple string literal concatenation, using space separation is the most straightforward and effective method. When dynamically generating identifiers or handling macro arguments, a layered macro design should be employed to control expansion timing. Special attention should be paid to avoiding direct use of the ## operator on string literals, as this leads to preprocessing errors.