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

Ser*_*kov 17 c gcc visual-studio c-preprocessor

我发现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)
Run Code Online (Sandbox Code Playgroud)

'gcc -E'给出以下内容:

a + {a + b}
Run Code Online (Sandbox Code Playgroud)

,'cl/E'发出关于缺少宏参数的警告并产生以下输出:

a + {a, b} +
Run Code Online (Sandbox Code Playgroud)

似乎来自嵌套宏扩展的逗号不被视为参数分隔符.不幸的是,我没有找到cl预处理器中实现的算法的描述,所以我不确定我的建议是否正确.有谁知道cl预处理器是如何工作的,它的算法和gcc之间有什么区别?以及如何解释观察到的行为?

Seb*_*ach 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)
Run Code Online (Sandbox Code Playgroud)

让我们一步一步地手动推出:

M(a, b)
--> M2(a, P(a, b))
--> M2(a, {a, b})
Run Code Online (Sandbox Code Playgroud)

标准说:

列表中的各个参数由逗号预处理标记分​​隔,但匹配内部括号之间的逗号预处理标记不会分开

只提到括号,所以......

--> M3(a, {a, b})
--> a + {a + b}
Run Code Online (Sandbox Code Playgroud)

重要:

M3(a, {a, b})
Run Code Online (Sandbox Code Playgroud)

在这里,根据标准的先前引用,三个"参数"被传递给M3(使用单引号来描述标记/参数):

M3('a', '{a', 'b}')
Run Code Online (Sandbox Code Playgroud)

这些扩展到了

'a' + '{a' + 'b}'
Run Code Online (Sandbox Code Playgroud)

这就是cpp(4.6.1)逐字给出的内容:

# 1 "cpp.cpp"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "cpp.cpp"




a + {a + b}
Run Code Online (Sandbox Code Playgroud)

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

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

  • AFAIR这个预处理器的精确规则来自C99.所以对于MSVC来说这不是一个bug,我认为他们声称不符合C99.如今,为MSVC编写的代码根本不可移植. (3认同)

Sin*_*all 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 
Run Code Online (Sandbox Code Playgroud)

海湾合作委员会方式:

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
Run Code Online (Sandbox Code Playgroud)

  • `cpp` 不认为有 3 个参数,它_知道_ 有,根据标准_有_ 三个参数。只有括号内的逗号不是“预处理器逗号”(旁注:我不会为此提出任何反对票,以防万一有人这样做):) (2认同)