为什么在重新扫描期间不会替换参数替换?

时间:2010-06-01 12:07:26

标签: c++ c-preprocessor

考虑以下宏定义和调用:

#define x x[0]
#define y(arg) arg

y(x)

此调用扩展为x[0](在Visual C ++ 2010,g ++ 4.1,mcpp 2.7.2和Wave上测试)。

为什么?具体来说,为什么它不会扩展到x[0][0]

在宏替换期间,

  

替换列表中的参数...在扩展了其中包含的所有宏之后被相应的参数替换。在被替换之前,每个参数的预处理标记都被完全宏替换(C ++03§16.3.1/ 1)。

评估宏调用,我们采取以下步骤:

  • 调用类似函数的宏yx作为其arg参数的参数
  • 参数中的x已被宏替换为x[0]
  • 替换列表中的arg将替换为参数的宏替换值x[0]

替换所有参数后的替换列表为x[0]

  

替换列表中的所有参数都被替换后,重新扫描生成的预处理标记序列...以替换更多的宏名称(C ++03§16.3.4/ 1)。

     

如果在替换列表的扫描过程中找到要替换的宏的名称,则不会替换它。此外,如果任何嵌套替换遇到要替换的宏的名称,则不会替换它(C ++03§16.3.4/ 2)。

重新扫描替换列表x[0](请注意要替换的宏的名称y):

  • x被标识为类似对象的宏调用
  • x已被x[0]
  • 取代

此时替换停止,因为§16.3.4/ 2中的规则阻止了递归。重新扫描后的替换列表为x[0][0]

我清楚地误解了一些东西,因为我测试的所有预处理器都说我错了。此外,这个例子是C ++ 0x FCD中的一个更大的例子(§16.3.5/ 5),它也说预期的替换是x[0]

为什么在重新扫描期间x没有被替换?

C99和C ++ 0x实际上与引用部分中的C ++ 03具有相同的措辞。

1 个答案:

答案 0 :(得分:17)

我相信你引用了关键段落,你刚刚停止了。 16.3.4 / 2(强调我的):

  

如果在此扫描期间找到要替换的宏的名称   替换清单(不包括   源文件的其余部分   预处理令牌),它不是   更换。此外,如果有任何嵌套   替换遭遇   要替换的宏的名称,   它没有被替换。 这些无法替代   宏名称预处理令牌是否定的   更长时间可用   更换即使他们以后   (重新)在其中检查   宏名称预处理令牌会   否则已被替换。

因此,在x的参数替换期间x[0]替换为y时,它会被完全宏替换,这意味着它会在那时重新扫描,{{1} }被递归规则捕获。这意味着x中的x不再有资格进行进一步替换,包括在重新扫描x[0]的部分扩展结果期间。