问题
I just noticed an interesting thing about the expansion of the macro parameters in C++.
I defined 4 macros; 2 of them turn given parameter into string and another 2 try to separate 2 arguments. I passed them argument with macro which expands into ,
and got the following results:
#define Quote(x) #x
#define String(x) Quote(x)
#define SeparateImpl(first, second) first + second
#define Separate(pair) SeparateImpl(pair)
#define comma ,
int main(){
Quote(1 comma 2); // -> "1 comma 2"
String(1 comma 2); // -> "1 , 2"
SeparateImpl(1 comma 2); // -> 1 , 2 + *empty arg*
Separate(1 comma 2); // -> 1 , 2 + *empty arg*
return 0;
}
So, as we see macro String turned into "1 , 2"
, that means macro comma had been unpacked first. However, macro Separate turned into 1 , 2 + **empty arg**
, that means macro comma
hadn't been unpacked first and I wonder why? I tried this in VS2019.
回答1:
#define Quote(x) #x
#define String(x) Quote(x)
#define SeparateImpl(first, second) first + second
#define Separate(pair) SeparateImpl(pair)
#define comma ,
Macro invocation proceeds as follows:
- Argument substitution (a.s), where if a parameter is mentioned in the replacement list and said parameter does not participate in a paste or stringification, it is fully expanded and said mentions of the parameter in the replacement list are substituted with the result.
- Stringification
- Pastes
- Rescan and further replacement (r.a.f.r.), where the resulting replacement list is rescanned, during which the macro's name is marked as invalid for expansion ("painted blue").
Here's how each case should expand:
Quote(1 comma 2)
a.s. no action (only mention of parameter is stringification). Stringification applies. Result: "1 comma 2"
.
String(1 comma 2)
a.s. applies; yielding Quote(1 , 2)
. During r.a.f.r., Quote
identified as a macro, but the argument count doesn't match. This is invalid. But see below.
SeparateImpl(1 comma 2)
Invalid macro call. The macro is being invoked with one argument, but it should have 2. Note that comma
being defined as a macro is irrelevant; at the level of macro invocation you're just looking at the tokens.
Separate(1 comma 2)
a.s. applies; yielding SeparateImpl(1 , 2)
. During r.a.f.r., SeparateImpl
is invoked... that invocation's a.s. applies, yielding 1 + 2
.
I tried this in VS2019.
I could tell from a glance it was VS something before 2020, where the walls tells me they're finally going to work on preprocessor compliance. VS in particular seems to have this strange state in which tokens with commas in them nevertheless are treated as single arguments (it's as if argument identification occurs before expansion but continues to apply or something); so in this case, 1 , 2
would be that strange thing in your String(1 comma 2)
call; i.e., Quote
is being called with 1 , 2
but in that case it's actually one argument.
来源:https://stackoverflow.com/questions/57476237/how-does-expansion-of-the-macro-parameters-work-in-c