C function syntax, parameter types declared after parameter list
我对C比较陌生。我遇到了一种我以前从未见过的函数语法形式,其中参数类型是在参数列表之后定义的。有人能给我解释一下它与典型的C函数语法有什么不同吗?
例子:
1 2 3 4 5 6 | int main (argc, argv) int argc; char *argv[]; { return(0); } |
型
这是参数列表的旧样式语法,仍然受支持。在K&R C中,您也可以不使用类型声明,它们将默认为int。
1 2 3 4 5 | main(argc, argv) char *argv[]; { return 0; } |
将具有相同的功能。
型
还有一个有趣的地方是函数与不带原型的函数之间的调用约定差异。考虑旧的样式定义:
1 2 3 4 | void f(a) float a; { /* ... */ } |
。
在这种情况下,调用约定是在传递给函数之前提升所有参数。因此,如果
如果包含原型,编译器将不再执行此类自动升级,并且传递的任何数据都将转换为原型的参数类型,就像通过赋值一样。因此,以下行为不合法,导致行为不明确:
1 2 3 4 5 | void f(float a); void f(a) float a; { } |
在这种情况下,函数的定义会将提交的参数从
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | // 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) { } |
。
如果您有选择的话,选项2应该是首选的,因为它会预先去掉旧的样式定义。如果函数的这种矛盾函数类型出现在同一翻译单元中,编译器通常会告诉您(但不是必需的)。如果这样的矛盾出现在多个翻译单元上,那么错误可能会被忽略,并且很难预测错误。最好避免使用这些旧的样式定义。
型
这是SO调用者k&r样式或旧样式声明。
请注意,本宣言与现代宣言有显著不同。K&R声明不会为函数引入原型,这意味着它不会向外部代码公开参数类型。
型
虽然函数定义的旧语法仍然有效(如果询问编译器,则会出现警告),但使用它们并不能提供函数原型。如果没有函数原型,编译器将不会检查函数是否被正确调用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
号
当程序运行时,我机器上的输出是
1 2 3 4 5 6 7 | $ 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年代的朋友。同样,不要依赖于隐含的类型假设(另一个答案似乎建议)
型
这只是一种古老的时尚。您可能发现它是一些旧的、遗留的代码。
型
不管老与否,我都会争论什么是旧,什么是新……就像金字塔是古老的,但今天所谓的科学家都不知道它们是如何在哪里形成的。回顾过去,旧的程序在今天仍然可以正常工作,没有内存泄漏,但是这些"新"程序往往比以前失败得多。我在这里看到了一种趋势。
可能他们将函数看作具有可执行体的结构。这里需要掌握ASM的知识来解开这个谜。
编辑,找到一个宏,指示您根本不需要提供参数名。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | #ifndef OF /* function prototypes */ # ifdef STDC # define OF(args) args # else # define OF(args) () # endif #endif #ifndef Z_ARG /* function prototypes for stdarg */ # if defined(STDC) || defined(Z_HAVE_STDARG_H) # define Z_ARG(args) args # else # define Z_ARG(args) () # endif #endif |
。
下面是一个使用示例,库是zlib-1.2.11。
1 | ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); |
所以我的第二个猜测是函数重载,否则这些参数就没有用处了。一个具体的函数,现在有无限多的同名函数。