复合文字和类似函数的宏:gcc或C标准中的错误?

时间:2011-04-05 20:33:50

标签: c gcc c-preprocessor c99 compound-literals

在C99中,我们有复合文字,它们可以传递给函数,如:

f((int[2]){ 1, 2 });

但是,如果f不是函数而是函数式宏,那么由于预处理器将其解析为不是一个参数而是作为两个参数,“(int[2]){ 1”和“2 }”。

这是gcc或C标准中的错误吗?如果它是后者,那几乎排除了所有透明使用类似函数的宏,这似乎是一个巨大的缺陷......

编辑:举例来说,人们会希望以下内容符合程序片段:

fgetc((FILE *[2]){ f1, f2 }[i]);

但由于fgetc可以作为宏实现(虽然需要保护其参数而不是多次评估它),但这段代码实际上是不正确的。这对我来说似乎很令人惊讶。

3 个答案:

答案 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正在按标准要求行事)。