在C99中,我们有复合文字,它们可以传递给函数,如:
f((int[2]){ 1, 2 });
但是,如果f
不是函数而是函数式宏,那么由于预处理器将其解析为不是一个参数而是作为两个参数,“(int[2]){ 1
”和“2 }
”。
这是gcc或C标准中的错误吗?如果它是后者,那几乎排除了所有透明使用类似函数的宏,这似乎是一个巨大的缺陷......
编辑:举例来说,人们会希望以下内容符合程序片段:
fgetc((FILE *[2]){ f1, f2 }[i]);
但由于fgetc
可以作为宏实现(虽然需要保护其参数而不是多次评估它),但这段代码实际上是不正确的。这对我来说似乎很令人惊讶。
答案 0 :(得分:8)
自C89以来,这个“bug”已存在于标准中:
#include <stdio.h>
void function(int a) {
printf("%d\n", a);
}
#define macro(a) do { printf("%d\n", a); } while (0)
int main() {
function(1 ? 1, 2: 3); /* comma operator */
macro(1 ? 1, 2: 3); /* macro argument separator - invalid code */
return 0;
}
我实际上没有查看标准来检查这个解析,我已经采用了gcc的话,但非正式地说,需要匹配:
到每个?
胜过运算符优先级和参数列表语法使第一个语句起作用。第二次没有这样的运气。
答案 1 :(得分:4)
这是按照C标准,与C ++中的方法类似,以下是一个问题:
f(ClassTemplate<X, Y>) // f gets two arguments: 'ClassTemplate<X' and 'Y>'
如果在C99中添加一些额外的括号是合法的,您可以使用:
f(((int[2]){ 1, 2 }));
^ ^
从C99§6.10.3/ 11中指定此行为的规则如下:
由最外部匹配括号限定的预处理标记序列 形成类似函数的宏的参数列表。
列表中的各个参数由逗号预处理标记分隔,但匹配内部括号之间的逗号预处理标记不会分隔参数。
答案 2 :(得分:1)
如果它完全是一个错误,那就是标准,而不是gcc(即,在这方面,我相信gcc正在按标准要求行事)。