旧版 K&R 样式声明/定义
当 Kernighan 和 Ritchie 第一次发表“The C Programming Language”时,C 还没有提供完整的函数原型。存在函数的前向声明,但其唯一目的是指示返回类型。对于返回 int 的函数,直到 C99 才需要它们。
在 C89 中,添加了函数原型的概念,它还指定了参数的类型(以及隐含的参数编号)。由于原型也是一种函数声明,非官方术语“K&R 函数声明”有时用于不是原型的函数声明。
// K&R declarations, we don't know whether these functions have parameters.
int foo(); // this declaration not strictly necessary until C99, because it returns int
float bar();
// Full prototypes, specifying the number and types of parameters
int foo(int);
float bar(int, float);
// K&R definition of a function
int foo(a)
int a; // parameter types were declared separately
{
// ...
return 0;
}
// Modern definition of a function
float bar(int a, float b)
{
// ...
return 0.0;
}
意外的 K&R 声明
值得注意的是,C 新手在打算使用完整原型时可能会意外使用 K&R 声明,因为他们可能没有意识到必须将空参数列表指定为 void。
如果你声明并定义一个函数为
// Accidental K&R declaration
int baz(); // May be called with any possible set of parameters
// Definition
int baz() // No actual parameters means undefined behavior if called with parameters.
// Missing "void" in the parameter list of a definition is undesirable but not
// strictly an error, no parameters in a definition does mean no parameters;
// still, it's better to be in the habit of consistently using "void" for empty
// parameter lists in C, so we don't forget when writing prototypes.
{
// ...
return 0;
}
...那么您实际上并没有为不带参数的函数提供原型,而是为接受未知数量的未知类型参数的函数提供了 K&R 样式的声明。
AnT 在this answer 中针对类似问题指出,该语法已被弃用,但自 C99 起仍然合法(并且指向具有未知数量和类型参数的函数的函数指针仍有潜在应用,尽管存在未定义行为的高风险);因此,如果在没有适当原型的情况下声明或调用函数,兼容的编译器最多会产生警告。
在没有原型的情况下调用函数不太安全,因为编译器无法验证您是否以正确的顺序传递了正确数量和类型的参数;如果调用实际上不正确,则会导致未定义的行为。
声明和定义无参数函数的正确方法当然是:
// Modern declaration of a parameterless function.
int qux(void); // "void" as a parameter type means there are no parameters.
// Without using "void", this would be a K&R declaration.
// Modern definition of a parameterless function
int qux(void)
{
// ...
return 0;
}