C语言 GNU cpp 是否对零参数的宏奇怪地解释 C99 标准



为什么GNU cpp接受以下代码,即使使用标志-std=c99 -pedantic运行:

#define z()
#define w(x)
z()
w()
w(1)

C99 标准要求类函数宏调用中的参数数应与宏定义中的参数数匹配(并且对参数可能包含预处理标记的空序列的想法感到满意,因此前两次调用可能提供单个空参数),但不能对所有三个调用都如此。

事实上,z 肯定只能用零参数调用,这在语法上是不可能的?

一些实验表明,第一行w被解释为一个空参数:

#define w(x) #x
w()
w(1)

预处理时得到:

""
"1"

甚至更好:

#define w(x, y) #x <-> #y
w(,)
w(1,)
w(, 2)
w(1, 2)

给:

"" <-> ""
"1" <-> ""
"" <-> "2"
"1" <-> "2"

漂亮。。。

不知道标准对此有何规定。必须问律师...

宏用法与函数调用在一个重要方面不同:宏参数可能为空。这是有效的:

#define x(a,b)  X a X b X
x(,)  //-> X X X
x(1,) //-> X 1 X X
x(,2) //-> X X 2 X

鉴于允许空参数,此宏用法:

#define x(a) X a X
x()  //-> X X

必须解释为空参数。虽然这个:

#define x() XX
x()  //-> XX

是一个没有参数的宏。

标准中唯一可以用来使用它的语言如下:

C 2011.第 6.10.3 节 宏替换。第10段的一部分:

格式的预处理指令:

# define identifier lparen identifier-list_opt ) replacement-list new-line
# define identifier lparen ... ) replacement-list new-line
# define identifier lparen identifier-list , ... ) replacement-list new-line

定义一个带有参数的类似函数的宏,其用途是 在语法上类似于函数调用。

话虽如此,该标准确实给出了有效宏替换的示例。它们包括:

#define p() int
#define t(a) a
#define glue(a, b) a ## b
p()       // Produces: int
t(x)      // Produces: x
glue(1,2) // Produces: 12

这里有一个语法歧义。 给定一个类似函数的宏调用x(),括号之间的空标记序列可以解释为没有参数,或者是一个空参数。 GCC 通过查看宏定义来解决歧义:

#define x()  replacement
#define y(a) repl##a##cement
x() y()

将预处理而不会出错

replacement replcement

我不再记住 C99 第 6.10 节,以至于我可以在头顶上说出为什么这是正确的行为,但我确信它是,因为如果不是这样,我会让 GCC 做其他事情。

https://gcc.gnu.org/onlinedocs/gcc-4.8.1/cpp/Macro-Arguments.html 的底部,以相对非正式的术语对这些规则进行了一些讨论。 特别要注意的是,给定的

#define z(a,b) stuff with a and b

z()是错误的,但z(,)是可以接受的。

最新更新