2014-07-11 50 views
4

我刚刚注意到GCC的行为,这对我来说似乎很陌生(未与其他编译器一起检查过)。调用带有太多参数的函数时的GCC行为

如果我编译此代码:

#include <stdio.h> 

void foo(int i) 
{ 
    printf("Hello %d\n",i); 
} 

int main(){ 
    foo(1, 2); 
    return 0; 
} 

我会得到一个编译错误:

test.c:9:5: error: too many arguments to function ‘foo’ 

但如果我编译此代码:

#include <stdio.h> 

void foo() 
{ 
    printf("Hello\n"); 
} 

int main(){ 
    foo(1, 2); 
    return 0; 
} 

我没有得到任何错误或警告。

有人能解释我为什么吗?

我用gcc 4.6.3试用了一下手臂,无 - EABI-GCC 4.8.3

编辑:我编译所有的警告:gcc -Wall test.c

+1

加上'-pedantic'获得更多的警告 – mch

+1

@mch谢谢你的提示,在这种情况下,它不会警告任何 – Quentin

+0

您需要-Wstrict的原型让海湾合作委员会警告它。 –

回答

6

在C中,编写void foo()意味着foo带有未指定数量的参数。

为了指示功能foo()应该采取任何参数,你应该写void foo(void)

出于这个原因,你也应该使用的签名int main(void)

+0

不错!我不知道为参数指定'void'是不同于将其保留为空 – Quentin

+1

@Quentin它仅在C中才是如此。在C++中,它们是同义词。 –

+1

@PascalCuoq'(void)'然而在C++中被弃用,因为它只是所述C规则的向后兼容的补余。另外,'main(void)',真的吗? – Quentin

2

打开你的警告!

void foo() 

是一种陈旧的ANSI C语言,它没有适当的原型来声明函数。如果你这样做,该函数的行为类似于void foo(...),并允许任意数量的参数传递。

(在C++中,void foo()声明了一个null-arity函数,就像你期望的那样)。

+1

我没有警告gcc -Wall test.c' – Quentin

+1

我想警告是编译器依赖的。我确实收到了Clang的警告。 – nneonneo

2

我会争辩说,gcc应该在这里抱怨。艾蒂安的答案应该是正确的,如果f是一个extern原型,但(在C996.7.6.3§14在C11,6.7.5.3§14)实际段落讨论这一点读取方式(重点煤矿):

标识符列表仅声明该函数参数的标识符。 作为函数定义的一部分的函数声明器中的空 列表指定 函数没有参数。函数声明器中的空列表不是该函数的 定义的一部分,它指定不提供有关参数数量或类型的信息。

clang(V3.4)确实发出警告(too many arguments in call to 'foo')与你的文件,但会愉快地(默默)编译下面的两个文件:

foo.c的:

extern void foo(); 
int main(){ 
    foo(1, 2); 
    return 0; 
} 

吧。C:

#include <stdio.h> 
void foo (int x, int y, int z) { printf("Hello %d\n", z); } 

结果:

$ clang -o foo bar.c foo.c 
$ ./foo 
Hello 1405669720 
+0

+1。你知道为什么gcc的行为如此吗?我搜索了gcc的文档,但没有找到任何参考。 –

+0

我不会不同意它*应该*警告,但我不相信这是必需的。具有空括号的函数定义不提供原型。它没有指定任何参数(在函数定义中可见的局部对象),但是(从奇怪的意义上)它没有指定该函数不需要*参数*。该语法是预ANSI C的遗留物;当时,编译器通常不会警告参数不匹配。教训:始终使用原型。 –

+0

使用gcc,你可以定义函数属性'__attribute__格式(类型,字符串,检查)',强制编译器根据格式字符串检查'printf()'或'scanf()'函数参数。 这可能是您在标准库标题中找到的内容。 – mfro