首页 > 解决方案 > 宏参数的扩展如何在c ++中工作

问题描述

我刚刚注意到关于 C++ 中宏参数扩展的一个有趣的事情。

我定义了 4 个宏;其中 2 个将给定参数转换为字符串,另外 2 个尝试分隔 2 个参数。我将宏传递给它们的参数,宏扩展为,并得到以下结果:

#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;
}

因此,当我们看到宏 String 变成"1 , 2"时,这意味着宏逗号已被首先解包。但是,宏分离变成了1 , 2 + **empty arg**,这意味着宏comma没有先被解包,我想知道为什么?我在 VS2019 中试过这个。

标签: c++c-preprocessor

解决方案


#define Quote(x) #x
#define String(x) Quote(x)
#define SeparateImpl(first, second) first + second
#define Separate(pair) SeparateImpl(pair)
#define comma ,

宏调用如下:

  • 参数替换 (as),如果在替换列表中提到了一个参数并且该参数不参与粘贴或字符串化,则它被完全扩展,并且替换列表中提到的参数被替换为结果。
  • 串化
  • 糊状物
  • 重新扫描和进一步替换 (rafr),其中重新扫描生成的替换列表,在此期间宏的名称被标记为对扩展无效(“涂成蓝色”)。

以下是每个案例应该如何扩展:

Quote(1 comma 2)

因为没有动作(只提到参数是字符串化)。字符串化适用。结果:"1 comma 2"

String(1 comma 2)

视情况而定;屈服Quote(1 , 2)。rafr 期间,Quote标识为宏,但参数计数不匹配。这是无效的。但见下文。

SeparateImpl(1 comma 2)

无效的宏调用。使用一个参数调用宏,但它应该有 2 个。请注意,comma定义为宏是无关紧要的;在宏调用级别,您只是在查看令牌。

Separate(1 comma 2)

视情况而定;屈服SeparateImpl(1 , 2)。在 rafr 期间,SeparateImpl被调用...该调用适用,产生1 + 2.

我在 VS2019 中试过这个。

我一眼就能看出它是 2020 年之前的 VS,那里的墙壁告诉我他们最终将致力于预处理器的合规性。特别是 VS 似乎有这种奇怪的状态,其中带有逗号的标记仍然被视为单个参数(就好像参数识别发生在扩展之前但继续应用或其他东西);所以在这种情况下,1 , 2你的电话会是那个奇怪的东西String(1 comma 2);即,Quote正在被调用,1 , 2但在这种情况下,它实际上是一个参数。


推荐阅读