K&R 函数声明和 ANSI 函数声明有什么区别?
3 回答
K&R 语法已过时,您可以跳过它,除非您必须维护非常旧的代码。
// K&R syntax
int foo(a, p)
int a;
char *p;
{
return 0;
}
// ANSI syntax
int foo(int a, char *p)
{
return 0;
}
旧版 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 在对类似问题的回答中指出,该语法已被弃用,但自 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;
}
我只是想在传统的 K & R 样式类型修饰符中添加返回int
值的函数,甚至不需要。
考虑一个简单的 HelloWorld 程序的现代 C11 表示法:
int main(int argc, char **argv) {
printf("hello world\n");
return 0;
}
这等效于 K & R 符号样式:
main(argc, argv)
int argc;
char **argv;
{
printf("hello world\n");
return 0;
}
请注意,忽略了int
之前main()
的代码,但代码仍然可以编译。这是 K&R 定义的一部分。
引用维基百科:
在 C 的早期版本中,如果在函数定义之前使用,则只有返回非 int 值的函数才需要声明;如果使用了没有任何先前声明的函数,则假定其返回类型为 int。
--来源: https ://en.wikipedia.org/wiki/C_(programming_language)#K.26R_C
这可以说是一种遗留的编码风格,由于清晰度问题应该避免,但旧的算法教科书通常更喜欢这种 K&R 风格。