首页 > 解决方案 > `int foo() {}` 与 `int foo(void) {}` 在声明 `int foo(void);` 之后的定义

问题描述

注意:这与 c99 中的 func() vs func(void)不同,因为这里的问题专门询问了在有效声明之后实现零参数函数。

零参数的实现是否应该包含void关键字?具体来说,C标准对下面两个函数的实现有什么要说的吗?请注意,foo1foo2都被声明为零参数函数;唯一的区别在于实现,而不是声明:

#include <stdio.h>

int foo1(void);  // inform compiler that foo1 and foo2 are zero-args fns.
int foo2(void);

int main() {
  printf("%d\n", foo1());
  printf("%d\n", foo2());
  return 0;
}

int foo1(void) { return 22; }
int foo2() { return 22; }

我注意到gcc -Wall -std=c99 -Wpedantic foo.c -o foo编译和执行没有任何警告或错误,但是是否有任何违反标准的行为?

标签: clanguage-lawyer

解决方案


您发布的代码是正确的。int foo2(void);声明foo2不带参数,并形成一个原型。

函数定义必须与此兼容;并且带有空括号的定义与此原型兼容。这是在 C11 6.7.6.3/15 中指定的,这是一口:

对于要兼容的两种函数类型,两者都应指定兼容的返回类型。此外,参数类型列表(如果两者都存在)应在参数数量和省略号终止符的使用方面达成一致;相应的参数应具有兼容的类型。如果一种类型具有参数类型列表,而另一种类型由不属于函数定义的函数声明符指定且包含空标识符列表,则参数列表不应有省略号终止符,并且每个参数的类型应与应用默认参数提升所产生的类型兼容。如果一种类型具有参数类型列表,而另一种类型由包含(可能为空)标识符列表的函数定义指定,则两者在参数数量上应一致,并且每个原型参数的类型应与类型兼容这是由于将默认参数提升应用于相应标识符的类型而产生的。(在类型兼容性和复合类型的确定中,每个声明为函数或数组类型的参数被视为具有调整后的类型,每个声明为合格类型的参数被视为具有其声明类型的非限定版本。)

关于这一点有这么多文字的原因是C最初只有K&R风格的函数,然后添加了原型。因此,必须有文字来涵盖 K&R 风格与原型风格混合的所有可能组合。以我的粗体部分开头的部分是指当函数先前已使用原型声明时使用 K&R 样式的函数定义。


同样相关:在 C11 (6.11.6) 中使用空括号已过时。

某些特性已经过时,这意味着它们可能会在本国际标准的未来修订版中被考虑撤销。由于它们的广泛使用,它们被保留下来,但不鼓励在新的实现或新程序中使用它们。


推荐阅读