为什么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(,)
是可以接受的。