2009-10-18 126 views
62

我对C来说比较新。我遇到过一种我从未见过的函数语法形式,其中参数类型是在该参数列表之后定义的。有人能向我解释它与典型的C函数语法有何不同吗?C函数语法,在参数列表之后声明的参数类型

例子:

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

回答

56

这对参数列表,仍支持旧风格的语法。在K & R C中,你也可以忽略类型声明,它们将默认为int。即

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

将是相同的功能。

+13

C89/90和C99都仍然正式支持K&R风格声明。但是,在C99中,所有参数都必须显式声明(不再有“隐式int”规则)。 – AnT 2009-10-18 17:12:11

+1

我讨厌晚会(比如4年后?),但是你的意思是说,在C99中,他们需要在参数列表中*或*在函数*中显式声明*?例如,默认的int规则 - 因为它们不再默认为int,那么它们的类型需要在使用之前在函数中声明**如果**类型未在参数列表中提供? – 2013-09-30 10:43:14

+1

@ChrisCirefice 4年后回答你:在C99中,所有参数必须在参数列表中声明。在函数中声明的变量从来没有默认为'int',因此必须明确声明。 – 2017-08-14 11:40:24

3

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

+0

C99前;它被用于ANSI之前,它在1989年被标准化了,但是这个过程始于1983年。 – 2009-10-18 16:53:39

+0

谢谢你的伴侣。现在修复它... – aviraldg 2009-10-18 17:04:49

+1

Ahem ... K&R风格的声明仍然由C99正式支持,只有一个小改动 - 不再有“隐式int”,所有参数都必须明确声明。 – AnT 2009-10-18 17:14:29

1

它只是一样的,但旧时尚。您可能会发现它是一些旧的旧版代码。

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 
10

这就是呼叫者ķ& [R风格旧式声明。

注意,这个声明是显着不同于现代的声明。 K & R声明不会为该函数引入原型,这意味着它不会将参数的类型暴露给外部代码。

24

还有一个有趣的地方是调用约定与函数的区别,以及没有原型的函数。考虑老式风格的定义:

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

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

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

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

} 

在这种情况下,该函数的定义将从double提交的参数(推广形式),因为定义是旧式转换为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应该是首选。如果函数的这种矛盾函数类型出现在同一个翻译单元中,编译器通常会告诉您(但不是必需的)。如果这种矛盾出现在多个翻译单元上,错误可能会被忽视,并可能导致很难预测错误。最好避免这些旧式的定义。