以下代码在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过于刺耳?
答案 0 :(得分:4)
来自 6.5.2.2函数调用:
2 - 如果表示被调用函数的表达式具有包含原型的类型,则 参数的数量应与参数的数量一致。 [...]
VC是故意允许的,以便允许编译(为了兼容)错误的代码。标准允许这样做,因为只要还发出诊断,就可以在遇到某些类型的错误代码时执行此类操作。
答案 1 :(得分:4)
该函数不带参数,但您传递参数。所以这是约束违规。在这种情况下,需要编译器发出诊断。所有三个编译器都发布了诊断信息,因此符合标准。但它是否被归类为 warning 或 error 是编译器的选择。
因此,Visual Studio中没有“bug”,只是在这种情况下GCC和clang更加严格。也许,VS实施者认为它不够严重,因为传递的参数将被忽略并决定仅发出警告,我只能推测。
答案 2 :(得分:2)
根据C99 gcc
和clang
都是正确的,参数列表中的void
表示它不带参数。从草案c99标准部分6.7.5.3
函数声明符(包括原型):
void类型的未命名参数的特殊情况,作为列表中的唯一项目 指定该函数没有参数。
但是由于Visual Studio正在发布诊断,因此它是一个有效的扩展。这与C4087的文档一致:
函数声明没有形式参数,但函数 call有实际参数。额外的参数根据传递 函数的调用约定。
此警告适用于C编译器。
虽然文档没有达到Visual Stuido 2013。
答案 3 :(得分:0)
您的代码是否绑定失败取决于调用约定,允许编译器构建器根据需要实现该约定。因此,一个编译器将其标记为错误而另一个编译器仅发出警告是合理的。但我几乎总是将编译器设置得尽可能严格,在MSVS的“警告错误”中 - 传递意外参数的最可能原因是你的一些错误。
答案 4 :(得分:-1)
当你用一个参数调用一个函数时,每个参数都被推送到你的调用堆栈上,然后你编程跳转到被调用的函数。然后,当你到达函数时,只删除了参数指定的数据,或者实际上堆栈指针只移动到函数声明指定的参数所需的范围。函数返回后,堆栈指针将不在propper位置,因为在函数调用期间它将移动太远。我不确定编译器如何处理这个问题,但是如果从多个函数返回,这似乎会导致问题。