【问题标题】:Why does a function prototype with an empty argument list conflicts with one that has a char argument?为什么具有空参数列表的函数原型与具有 char 参数的函数原型冲突?
【发布时间】:2014-03-18 11:36:50
【问题描述】:

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

int foo();

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

int foo(char a) {
   return a;
}

根据https://stackoverflow.com/a/13950800/1078224 中的答案,在(旧的?)C 标准中,当没有给出变量类型时,假定类型 int。但是,C11 标准草案 (http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf),第 6.7.6.3 节,$14 说

函数声明器中的空列表不属于 该函数的定义指定没有关于函数的数量或类型的信息 提供参数。

由此我得出结论,上面的代码实际上应该是有效的。还是我错过了标准的其他相关部分?

【问题讨论】:

  • 令人困惑的事实是总是使用原型的另一个论据。
  • 注意行号——错误在函数definition的行,而不是函数call的行。 ideone.com/mi5Eq2
  • 隐式 int 规则在 1999 年标准中被删除。

标签: c gcc clang standards c11


【解决方案1】:

C 2011 (N1570) 6.7.6.3 15:

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

char 被提升为int,因此char a 与空列表不兼容。 int a 将是; int foo(); int foo(int a); 是允许的。

本质上,这样做的原因是,如果你声明一个函数int foo() 然后调用它,比如int foo(3),编译器必须知道要传递什么。源自历史的规则将执行默认参数提升。所以int foo(3) 被称为int foo(int)

然后,如果您稍后使用int foo(char) 定义函数,则定义将与调用不匹配。在许多 C 实现中,charint 可能放在同一个位置来调用函数,但 C 实现可以做一些不同的事情。 floatdouble 会产生更大的冲突。

【讨论】:

  • 我还要注意,即使没有前向声明,也会出现类型冲突问题,因为对函数的实际调用(发生在文件中比函数定义更早的位置)使用 int , 和char 还是有区别的。
  • 我认为int foo();int foo(int); 也不一定兼容;我知道一些实现,其中对函数int foo(); 的调用将始终将参数放在堆栈上,而对int foo(int) 的调用将其参数放在寄存器中。唯一适用“默认 int”的地方是函数返回类型。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-04
相关资源
最近更新 更多