我对C比较陌生。我遇到过一种我以前从未见过的函数语法,其中参数类型是在参数列表之后定义的。有人可以向我解释它与典型的C函数语法有何不同?
示例:
int main (argc, argv)
int argc;
char *argv[];
{
return(0);
}
答案 0 :(得分:61)
这是参数列表的旧式语法,仍然受支持。在K& R C中,您也可以省略类型声明,它们将默认为int。即。
main(argc, argv)
char *argv[];
{
return 0;
}
将是相同的功能。
答案 1 :(得分:27)
有趣的是函数的调用约定差异,以及没有原型的函数。考虑旧样式定义:
void f(a)
float a; {
/* ... */
}
在这种情况下,调用约定是在传递给函数之前提升所有参数。因此,如果f
收到double
但参数的类型为float
(完全有效),则编译器必须发出代码,在执行函数体之前将double转换为float。
如果包含原型,则编译器不再执行此类自动提升,并且传递的任何数据都将转换为原型参数的类型,就像通过赋值一样。因此,以下内容不合法,导致未定义的行为:
void f(float a);
void f(a)
float a; {
}
在这种情况下,函数的定义会将提交的参数从double
(提升的形式)转换为float
,因为定义是旧式的。但是参数是作为float提交的,因为该函数有一个原型。你解决矛盾的选择是以下两点:
// 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,因为它预先删除了旧样式定义。如果函数的这些矛盾函数类型出现在同一个转换单元中,编译器通常会告诉您(但不是必需的)。如果在多个翻译单元上出现此类矛盾,则错误可能会被忽视,并且可能导致难以预测的错误。最好避免使用这些旧的样式定义。
答案 2 :(得分:10)
这是如此来电的 K& R风格或旧式声明。
请注意,此声明显着与现代声明不同。 K& R声明没有为函数引入原型,这意味着它不会将参数类型公开给外部代码。
答案 3 :(得分:4)
虽然函数定义的旧语法仍然有效(如果你问你的编译器会有警告),使用它们不会提供函数原型。
如果没有函数原型,编译器将不会检查函数是否被正确调用。
#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
答案 4 :(得分:3)
没有区别,只是这是C中函数声明的旧语法 - 它是在ANSI之前使用的。 永远不要编写此类代码,除非您打算将其提供给80年代的朋友。此外,永远不会依赖隐式类型假设(正如另一个答案似乎暗示的那样)
答案 5 :(得分:1)
它只是旧时尚。您可能发现它是一些旧的遗留代码。
答案 6 :(得分:0)
无论古老与否,我都会争论什么古老和什么……像金字塔一样古老,但是今天所谓的科学家都不知道它们是如何制造的。回顾过去,今天的旧程序仍然可以正常工作,而不会发生内存泄漏,但是这些“新”程序往往会失败的频率更高。我在这里看到趋势。
可能他们将函数视为具有可执行主体的结构。这里需要了解ASM才能解决这个难题。
编辑,发现一个宏,它指示您根本不需要提供参数名称。
#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。
ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush));
所以我的第二个猜测是函数重载,否则这些参数没有用。一个具体的功能,现在无限数量的同名功能。