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

时间:2021-06-06 02:12:38

I discovered that Microsoft Visual Studio compiler and gcc preprocess the following small snippet differently:

我发现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' gives the following:

“gcc -E”给出如下内容:

a + {a + b}

, while 'cl /E' issues a warning about missing macro argument and produces the following output:

,而“cl /E”则发出关于丢失宏参数的警告,并产生以下输出:

a + {a, b} +

It seems that commas that came from nested macro expansions are not considered to be argument separators. Unfortunately, I found no description of the algorithm implemented in cl preprocessor, and so I'm not sure that my suggestion is correct. Does anyone know how cl preprocessor works and what's the difference between its algorithm and gcc's? And how the observed behaviour can be explained?

似乎来自嵌套宏扩展的逗号不被认为是参数分隔符。不幸的是,我没有发现在clpreprocessor中实现的算法的描述,所以我不确定我的建议是否正确。有人知道cl预处理器是如何工作的吗?它的算法和gcc的有什么不同?如何解释观察到的行为?

3 个解决方案

#1


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)

Let us roll this out manually, step by step:

让我们一步一步手工推出:

M(a, b)
--> M2(a, P(a, b))
--> M2(a, {a, b})

The standard says:

标准的说:

The individual arguments within the list are separated by comma preprocessing tokens, but comma preprocessing tokens between matching inner parentheses do not separate

列表中的各个参数由逗号预处理令牌分隔,但是匹配的内部圆括号之间的逗号预处理令牌并不分开

only parentheses are mentioned, so ...

只提到括号,所以……

--> M3(a, {a, b})
--> a + {a + b}

Important:

重要的是:

M3(a, {a, b})

Here, according to the previous quote from the standard, three "arguments" are passed to M3 (using single-quotes to describe tokens/arguments):

这里,根据之前的标准引用,有三个“参数”传递给M3(使用单引号来描述令牌/参数):

M3('a', '{a', 'b}')

which are expanded to

这是扩大到

'a' + '{a' + 'b}'

And this is what cpp (4.6.1) gives verbatim:

这是cpp(4。6.1)给出的逐字表示:

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




a + {a + b}

cpp (or gcc and g++) are correct, MSVC isn't.

cpp(或gcc和g++)是正确的,MSVC不是。

As a nobleman make sure a bug report exists.

作为一个贵族,确保一个bug报告存在。

#2


4  

The only logic that explains such a behavior looks like this.

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

CL way:

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 way:

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

#3


1  

I think gcc gets it right, what Microsoft does is incorrect.

我认为gcc的做法是对的,微软的做法是错误的。

When macro substitution is done for the line

当行进行宏替换时

M2(a, P(a, b))

the standard (section 6.10.3.1) requires that before replacing the second parameter ("y") in the macro's replacement list ("M3(x, y)") with its argument ("P(a, b)"), macro replacement is to be performed for that argument. This means "P(a, b)" is processed to "{a, b}" before it is inserted, resulting in

标准(第6.10.3.1节)要求在将宏的替换列表中的第二个参数(“y”)(“M3(x, y)”)替换为其参数(“P(a, b)”之前,对该参数执行宏替换。这意味着“P(a, b)”在插入之前被处理为“{a, b}”,从而导致

M3(a, {a, b})

which is then further replaced to

然后又被取代了?

a + {a + b}

#1


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)

Let us roll this out manually, step by step:

让我们一步一步手工推出:

M(a, b)
--> M2(a, P(a, b))
--> M2(a, {a, b})

The standard says:

标准的说:

The individual arguments within the list are separated by comma preprocessing tokens, but comma preprocessing tokens between matching inner parentheses do not separate

列表中的各个参数由逗号预处理令牌分隔,但是匹配的内部圆括号之间的逗号预处理令牌并不分开

only parentheses are mentioned, so ...

只提到括号,所以……

--> M3(a, {a, b})
--> a + {a + b}

Important:

重要的是:

M3(a, {a, b})

Here, according to the previous quote from the standard, three "arguments" are passed to M3 (using single-quotes to describe tokens/arguments):

这里,根据之前的标准引用,有三个“参数”传递给M3(使用单引号来描述令牌/参数):

M3('a', '{a', 'b}')

which are expanded to

这是扩大到

'a' + '{a' + 'b}'

And this is what cpp (4.6.1) gives verbatim:

这是cpp(4。6.1)给出的逐字表示:

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




a + {a + b}

cpp (or gcc and g++) are correct, MSVC isn't.

cpp(或gcc和g++)是正确的,MSVC不是。

As a nobleman make sure a bug report exists.

作为一个贵族,确保一个bug报告存在。

#2


4  

The only logic that explains such a behavior looks like this.

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

CL way:

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 way:

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

#3


1  

I think gcc gets it right, what Microsoft does is incorrect.

我认为gcc的做法是对的,微软的做法是错误的。

When macro substitution is done for the line

当行进行宏替换时

M2(a, P(a, b))

the standard (section 6.10.3.1) requires that before replacing the second parameter ("y") in the macro's replacement list ("M3(x, y)") with its argument ("P(a, b)"), macro replacement is to be performed for that argument. This means "P(a, b)" is processed to "{a, b}" before it is inserted, resulting in

标准(第6.10.3.1节)要求在将宏的替换列表中的第二个参数(“y”)(“M3(x, y)”)替换为其参数(“P(a, b)”之前,对该参数执行宏替换。这意味着“P(a, b)”在插入之前被处理为“{a, b}”,从而导致

M3(a, {a, b})

which is then further replaced to

然后又被取代了?

a + {a + b}