C函数语法,参数列表后声明的参数类型

时间:2009-10-18 16:46:53

标签: c syntax function

我对C比较陌生。我遇到过一种我以前从未见过的函数语法,其中参数类型是在参数列表之后定义的。有人可以向我解释它与典型的C函数语法有何不同?

示例:

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

7 个答案:

答案 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));

所以我的第二个猜测是函数重载,否则这些参数没有用。一个具体的功能,现在无限数量的同名功能。