请考虑以下宏定义和调用:
#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
被标识为类似对象的宏调用 -
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 回答
我相信你已经引用了关键段落,你刚刚停止了 . 16.3.4 / 2(强调我的):
因此,当在
y
的参数替换期间x
被x[0]
替换时,它被完全宏替换,这意味着它在那时被重新扫描,并且递归规则捕获了x
. 这意味着x[0]
中的x
不再符合进一步替换的条件,包括在重新扫描y(x)
的部分扩展结果期间 .