C函数语法,在参数列表之后声明的参数types

我对C相对来说比较陌生。我遇到过一种我从未见过的函数语法forms,参数types是在参数列表之后定义的。 有人可以向我解释它是如何不同于典型的C函数语法?

例:

int main (argc, argv) int argc; char *argv[]; { return(0); } 

这是参数列表的旧式语法,仍然受支持。 在K&R C中,你也可以忽略types声明,并且默认为int。 即

 main(argc, argv) char *argv[]; { return 0; } 

将是相同的function。

另外有趣的是,调用约定与function的区别,以及没有原型的function。 考虑一个旧式的定义:

 void f(a) float a; { /* ... */ } 

在这种情况下,调用约定是所有参数在传递给函数之前都被提升。 所以如果f收到一个double但是参数的types为float (这是完全有效的),编译器必须发出代码,在执行函数体之前将double转换为float。

如果包含原型,编译器不再进行这种自动升级,并且任何传递的数据都将被转换为原型的参数types,就像通过赋值一样。 所以以下是不合法的,并导致未定义的行为:

 void f(float a); void f(a) float a; { } 

在这种情况下,函数的定义会将提交的参数从double (提升的表单)转换为float因为定义是旧式的。 但是这个参数是以浮点forms提交的,因为这个函数有一个原型。 解决矛盾的办法有以下两种:

 // option 1 void f(double a); void f(a) float a; { } // option 2 // this declaration can be put in a header, but is redundant in this case, // since the definition exposes a prototype already if both appear in a // translation unit prior to the call. void f(float a); void f(float a) { } 

select2应该是首选,如果你有select,因为它前面摆脱了旧的风格定义。 如果函数的这种矛盾的函数types出现在同一个翻译单元中,编译器通常会告诉你(但不是必需的)。 如果这样的矛盾出现在多个翻译单位上,这个错误可能会被忽视,并可能导致难以预料的错误。 最好避免这些旧式的定义。

这是如此来电的K&R风格旧式的声明。

请注意,这个声明与现代声明有很大的不同。 K&R声明不会为函数引入原型 ,这意味着它不会将参数的types暴露给外部代码。

虽然旧的函数定义语法仍然有效(有警告,如果你问你的编译器),使用它们不提供函数原型。
如果没有函数原型,编译器将不会检查函数是否被正确调用。

 #include <stdio.h> int foo(c) int c; { return printf("%d\n", c); } int bar(x) double x; { return printf("%f\n", x); } int main(void) { foo(42); /* ok */ bar(42); /* oops ... 42 here is an `int`, but `bar()` "expects" a `double` */ return 0; } 

当程序运行时,我的机器上的输出是

 $ gcc proto.c $ gcc -Wstrict-prototypes proto.c proto.c:4: warning: function declaration isn't a prototype proto.c:10: warning: function declaration isn't a prototype $ ./a.out 42 0.000000 

没有什么区别,只不过是C语言中旧函数声明的语法 – 在ANSI之前使用过。 不要写这样的代码,除非你打算把它交给80年代的朋友 。 另外, 从不依赖隐式types假设 (如另一个答案似乎表明)

它只是老样子。 您可能会发现这是一些旧的,遗留的代码。