首页 文章

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

提问于
浏览
12

请考虑以下宏定义和调用:

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

y(x)

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

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

在宏替换期间,

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

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

  • 使用 x 调用类似函数的宏 y 作为其 arg 参数的参数

  • 参数中的 x 被宏替换为 x[0]

  • 替换列表中的 arg 被参数的宏替换值 x[0] 替换

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

替换替换列表中的所有参数后,重新扫描生成的预处理标记序列...以替换更多的宏名称(C03§16.3.4/ 1) . 如果在替换列表的扫描期间找到要替换的宏的名称...则不会替换它 . 此外,如果任何嵌套替换遇到要替换的宏的名称,则不会替换它(C03§16.3.4/ 2) .

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

  • x 被标识为类似对象的宏调用

  • xx[0] 取代

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

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

为什么在重新扫描期间没有更换 x

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

1 回答

  • 17

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

    如果在替换列表的扫描期间找到要替换的宏的名称(不包括源文件的其余预处理标记),则不会替换它 . 此外,如果任何嵌套替换遇到要替换的宏的名称,则不会替换它 . 这些未替换的宏名称预处理令牌不再可用于进一步替换,即使它们稍后(重新)检查在其中否则将替换该宏名称预处理令牌的上下文中 .

    因此,当在 y 的参数替换期间 xx[0] 替换时,它被完全宏替换,这意味着它在那时被重新扫描,并且递归规则捕获了 x . 这意味着 x[0] 中的 x 不再符合进一步替换的条件,包括在重新扫描 y(x) 的部分扩展结果期间 .

相关问题