为什么具有空参数列表的函数原型与具有char参数的函数原型冲突?

为什么具有空参数列表的函数原型与具有char参数的函数原型冲突?,c,gcc,clang,standards,c11,C,Gcc,Clang,Standards,C11,在下面的代码中,使用-std=c11调用的clang和gcc都会抱怨foo的类型冲突 int foo(); int main(void) { return foo(0); } int foo(char a) { return a; } 根据中的答案,在(旧的?)C标准中,在没有给出变量类型的情况下,假定了int类型。然而,C11标准草案()第6.7.6.3节,$14指出 函数声明符中的空列表,它不是 该函数的定义指定没有关于函数的数量或类型的信息 提供了参数 由此我得出结论,上面

在下面的代码中,使用-std=c11调用的clang和gcc都会抱怨foo的类型冲突

int foo();

int main(void) {
  return foo(0);
}

int foo(char a) {
   return a;
}
根据中的答案,在(旧的?)C标准中,在没有给出变量类型的情况下,假定了int类型。然而,C11标准草案()第6.7.6.3节,$14指出

函数声明符中的空列表,它不是 该函数的定义指定没有关于函数的数量或类型的信息 提供了参数

由此我得出结论,上面的代码实际上应该是有效的。还是我遗漏了本标准的其他相关章节?

C 2011(N1570)6.7.6.3 15:

对于要兼容的两种功能类型,两者都应指定兼容的返回类型。此外,参数类型列表(如果两者都存在)应在参数数量和省略号终止符的使用方面保持一致;相应参数应具有兼容类型。如果一种类型具有参数类型列表,而另一种类型由不属于函数定义一部分且包含空标识符列表的函数声明符指定,参数列表不应具有省略号终止符,每个参数的类型应与应用默认参数升级时产生的类型兼容。…[重点已添加。]

char
升级为
int
,因此
char a
与空列表不兼容<代码>int a将是<代码>intfoo();int foo(int a)是允许的

本质上,这是因为,如果您声明一个函数
intfoo()
,然后调用它,比如用
intfoo(3)
,编译器必须知道传递它的内容。从历史中派生的规则用于执行默认参数升级。因此,
intfoo(3)
被调用,就好像它是
intfoo(int)


然后,如果以后使用
intfoo(char)
定义函数,则定义将与调用不匹配。在许多C实现中,
char
int
可以放在同一个位置来调用函数,但是C实现可以做一些不同的事情。
float
double
将是一个更大的冲突。

这是一个令人困惑的事实,这是始终使用原型的另一个理由。请注意行号——错误在函数定义的行上,而不是函数调用的行上。隐式
int
规则在1999年的标准中被删除。我还要注意的是,即使没有转发声明,也会有冲突的类型问题,因为对函数的实际调用(发生在函数定义之前)使用了
int
,这仍然不同于
char
intfoo(int)也必须兼容;我知道一些实现中调用函数
intfoo()
将始终将参数放在堆栈上,而调用
intfoo(int)
将其参数放在寄存器中。唯一适用于“defaultint”的地方是函数返回类型。