将参数发送到具有0个参数的函数时的行为不一致

时间:2015-05-01 12:03:31

标签: c gcc visual-studio-2013 clang

以下代码在clang(3.6.0)和gcc(4.9.2)(coliru link)上产生编译错误

#include <stdio.h>                      

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

int main(void)
{
    foo(1, 2, 3, 4, 5, 6, 67);
    return 0;
}

虽然VS2013(使用/ TC / W4编译时)仅产生警告

  

警告C4087:&#39; foo&#39; :声明&#39; void&#39;参数列表... 9 1

这是VC中的错误还是clang和gcc过于刺耳?

5 个答案:

答案 0 :(得分:4)

来自 6.5.2.2函数调用

  

2 - 如果表示被调用函数的表达式具有包含原型的类型,则   参数的数量应与参数的数量一致。 [...]

VC是故意允许的,以便允许编译(为了兼容)错误的代码。标准允许这样做,因为只要还发出诊断,就可以在遇到某些类型的错误代码时执行此类操作。

答案 1 :(得分:4)

该函数不带参数,但您传递参数。所以这是约束违规。在这种情况下,需要编译器发出诊断。所有三个编译器都发布了诊断信息,因此符合标准。但它是否被归类为 warning error 是编译器的选择。

因此,Visual Studio中没有“bug”,只是在这种情况下GCC和clang更加严格。也许,VS实施者认为它不够严重,因为传递的参数将被忽略并决定仅发出警告,我只能推测。

答案 2 :(得分:2)

根据C99 gccclang都是正确的,参数列表中的void表示它不带参数。从草案c99标准部分6.7.5.3函数声明符(包括原型):

  

void类型的未命名参数的特殊情况,作为列表中的唯一项目   指定该函数没有参数。

但是由于Visual Studio正在发布诊断,因此它是一个有效的扩展。这与C4087的文档一致:

  

函数声明没有形式参数,但函数   call有实际参数。额外的参数根据传递   函数的调用约定。

     

此警告适用于C编译器。

虽然文档没有达到Visual Stuido 2013。

答案 3 :(得分:0)

您的代码是否绑定失败取决于调用约定,允许编译器构建器根据需要实现该约定。因此,一个编译器将其标记为错误而另一个编译器仅发出警告是合理的。但我几乎总是将编译器设置得尽可能严格,在MSVS的“警告错误”中 - 传递意外参数的最可能原因是你的一些错误。

答案 4 :(得分:-1)

当你用一个参数调用一个函数时,每个参数都被推送到你的调用堆栈上,然后你编程跳转到被调用的函数。然后,当你到达函数时,只删除了参数指定的数据,或者实际上堆栈指针只移动到函数声明指定的参数所需的范围。函数返回后,堆栈指针将不在propper位置,因为在函数调用期间它将移动太远。我不确定编译器如何处理这个问题,但是如果从多个函数返回,这似乎会导致问题。