我发现Microsoft Visual Studio编译器和gcc以不同的方式预处理以下小片段:
# define M3(x, y, z) x + y + z
# define M2(x, y) M3(x, y)
# define P(x, y) {x, y}
# define M(x, y) M2(x, P(x, y))
M(a, b)
' gcc -E'给出以下内容:
a + {a + b}
,而' cl / E'发出关于缺少宏参数的警告并产生以下输出:
a + {a, b} +
似乎来自嵌套宏扩展的逗号不被视为参数分隔符。不幸的是,我没有找到cl预处理器中实现的算法的描述,因此我不确定我的建议是否正确。有谁知道cl预处理器如何工作以及它的算法和gcc的区别是什么?以及如何解释观察到的行为?
答案 0 :(得分:9)
# define M3(x, y, z) x + y + z
# define M2(x, y) M3(x, y)
# define P(x, y) {x, y}
# define M(x, y) M2(x, P(x, y))
M(a, b)
让我们一步一步地手动推出:
M(a, b)
--> M2(a, P(a, b))
--> M2(a, {a, b})
标准说:
列表中的各个参数用逗号分隔 预处理标记,但匹配内括号之间的逗号预处理标记不会分开
只提到括号,所以......
--> M3(a, {a, b})
--> a + {a + b}
重要的:
M3(a, {a, b})
在这里,根据标准的先前引用,三个“参数”被传递给M3(使用单引号来描述标记/参数):
M3('a', '{a', 'b}')
扩展为
'a' + '{a' + 'b}'
这就是cpp
(4.6.1)逐字提供的内容:
# 1 "cpp.cpp"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "cpp.cpp"
a + {a + b}
cpp
(或gcc
和g++
)是正确的,MSVC不是。
作为贵族,请确保存在错误报告。
答案 1 :(得分:4)
解释这种行为的唯一逻辑就是这样。
CL方式:
M(a,b)
M2(a,P(a,b))
M3(a,P(a,b))
M3(a,{a,b}) -> M3 gets 2 arguments ( 'a' and '{a,b}') instead of 3.
| \ /
arg1 |
arg2
Gcc方式:
M(a,b)
M2(a,P(a,b))
M3(a,P(a,b))
M3(a,{a,b}) -> Gcc probably thinks there are 3 arguments here ('a', '{a', 'b}').
| | |
arg1 | |
arg2 |
arg3
答案 2 :(得分:1)
我认为gcc是正确的,微软所做的不正确。
当对行进行宏替换时
M2(a, P(a, b))
标准(第6.10.3.1节)要求在用其参数(“P(a,b)”替换宏的替换列表(“M3(x,y)”)中的第二个参数(“y”)之前),将对该参数执行宏替换。这意味着“P(a,b)”在插入之前被处理为“{a,b}”,从而产生
M3(a, {a, b})
然后进一步替换为
a + {a + b}