我对C还是比较陌生。我遇到了一种从未见过的函数语法形式,其中参数类型在该参数列表之后定义。有人可以向我解释它与典型的C函数语法有何不同?
例:
int main (argc, argv)
int argc;
char *argv[];
{
return(0);
}
Answers:
这是参数列表的旧式语法,目前仍受支持。在K&R C中,您也可以省略类型声明,它们将默认为int。即
main(argc, argv)
char *argv[];
{
return 0;
}
将具有相同的功能。
int
,因此必须显式声明。
有趣的是,带有原型的函数和没有原型的函数的调用约定区别。考虑一个旧样式的定义:
void f(a)
float a; {
/* ... */
}
在这种情况下,调用约定是在将所有参数传递给函数之前将其提升(例如,在传递float
参数double
之前首先将其提升为)。因此,如果f
接收到一个double
但参数具有类型float
(完全有效)的类型,则编译器必须在执行函数的主体之前发出将double转换为float的代码。
如果包含原型,则编译器不再进行此类自动升级,并且传递的任何数据都将转换为原型的参数类型,就像通过分配一样。因此,以下内容不合法,并导致未定义的行为:
void f(float a);
void f(a)
float a; {
}
在这种情况下,该函数的定义会将提交的参数从double
(升级的表单)转换为,float
因为该定义是旧样式。但是参数是作为浮点数提交的,因为该函数具有原型。例如,clang给
main.c:3:9:警告:K&R函数参数的提升类型'double'与先前原型中声明的参数类型'float'不兼容[-Wknr-promoted-parameter]
您可以选择以下两种解决矛盾的方法:
// 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,因为它可以预先消除旧样式的定义。如果某个函数的此类矛盾函数类型出现在同一转换单元中,则编译器通常会告诉您(但不是必需的)。如果这些矛盾出现在多个翻译单元上,则该错误可能会被忽略,并可能导致难以预测的错误。最好避免使用这些旧样式定义。
没什么不同,只是这是C中函数声明的旧语法-它在ANSI之前使用。除非您打算将其提供给80年代的朋友,否则请不要编写此类代码。而且,永远不要依赖隐式类型假设(正如另一个答案似乎暗示的那样)
尽管用于函数定义的旧语法仍然可以使用(如果您询问编译器,则带有警告),但是使用它们不能提供函数原型。
没有函数原型,编译器将不会检查函数是否被正确调用。
#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
不论金字塔的古老与否,我都会争论,金字塔是古老的,还是古老的,但是今天所谓的科学家都不知道它们是如何制造的。回顾过去,旧程序在今天仍然可以正常工作,而不会发生内存泄漏,但是这些“新”程序往往会失败的频率更高。我在这里看到趋势。
他们可能将函数视为具有可执行主体的结构。这里需要了解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));
所以我的第二个猜测是函数重载,否则这些参数没有用。一个具体的功能,现在无限数量的同名功能。