gcc和Microsoft预处理器之间的区别

我发现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之间有什么区别? 以及如何解释观察到的行为?

 # 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 "" # 1 "" # 1 "cpp.cpp" a + {a + b} 

cpp (或gccg++ )是正确的,MSVC不是。

作为贵族,请确保存在错误报告。

解释这种行为的唯一逻辑就是这样。

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 

我认为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}