我不明白为什么会发生这种代码编译?
#include <stdio.h>
void foo() {
printf("Hello\n");
}
int main() {
const char *str = "bar";
foo(str);
return 0;
}
GCC甚至不扔,我传递的参数太多为foo()的警告。 这是预期的行为?
我不明白为什么会发生这种代码编译?
#include <stdio.h>
void foo() {
printf("Hello\n");
}
int main() {
const char *str = "bar";
foo(str);
return 0;
}
GCC甚至不扔,我传递的参数太多为foo()的警告。 这是预期的行为?
在C中,用空的参数列表中声明的函数接受时被调用的参数,这是受通常的算术优惠的任意数量。 这是来电者的责任,以确保所提供的参数是适用于函数的定义。
声明函数取零点的参数,你需要写void foo(void);
。
这是历史原因; 最初,C函数没有原型,为C演变而来乙 ,无类型语言。 当加入的原型,原无类型声明留在向后兼容的语言。
为了让GCC警告有关参数列表为空,则使用-Wstrict-prototypes
:
警告如果一个函数被声明或没有指定参数的类型定义。 (一种旧式函数定义被允许不如果前面的声明它指定了参数类型的警告。)
对于遗留原因,声明函数()
的参数列表基本上意味着“找出参数时调用该函数”。 要指定函数没有参数,使用(void)
。
编辑:我觉得我在这个问题费尽了被美誉为老。 只要你的孩子知道什么编程中使用的是一样,这里是我的第一个程序 。 (不是C,它可以显示你我们不得不在此之前的工作。)
void foo() {
printf("Hello\n");
}
foo(str);
在C,此代码不违反了约束(它将如果它在其原型的形式被定义void foo(void) {/*...*/}
并由于没有违反约束,编译器不必须发出诊断。
但此方案已按照下面的C规则未定义的行为:
从:
(C99,6.9.1p7)“如果声明符包括参数类型列表,该列表还指定类型的所有参数的;这样的说明符还用作函数原型供以后调用在相同的翻译单元相同的功能。如果声明符包括标识符列表,142)的类型的参数应在以下声明列表中声明“。
在foo
功能不提供一台样机。
从:
(C99,6.5.2.2p6)“如果它表示所调用的函数的表达有一个类型不包括一个原型[...]如果参数的数量不等于参数的数量,该行为是未定义”。
在foo(str)
函数的调用是不确定的行为。
C不授权,以发行诊断为调用不确定的行为,但你的程序仍然是一个错误的程序的程序执行。
无论是C99标准(6.7.5.3)和C11标准(6.7.6.3)状态:
标识符列表只声明了该函数的参数的标识符。 在一个函数声明是该函数的定义的一部分空列表指定的函数没有参数。 在一个函数声明是不是该函数的定义的一部分的空列表指定没有关于参数的数目或类型的信息被提供。
由于foo的声明是一个定义的一部分,该声明指定FOO取0参数,所以调用了foo(STR)是至少不道德的。 但是,如下所述,有不同程度的在C“错了”,和编译器可能在如何处理某些类型的“错误”是不同的。
举一个稍微简单的例子,考虑下面的程序:
int f() { return 9; }
int main() {
return f(1);
}
如果我编译上面使用锵:
tmp$ cc tmp3.c
tmp3.c:4:13: warning: too many arguments in call to 'f'
return f(1);
~ ^
1 warning generated.
如果我用gcc编译4.8我没有得到任何错误或警告,甚至-Wall。 使用-Wstrict的原型,它正确地报告f的定义不以原型形式前面的回答建议,但是这是真的不是重点。 的C标准(多个)允许以非原型形式的函数定义如上面的一个和所述标准明确指出,这个定义规定,函数采用0的参数。
现在有一个约束 (C11秒6.5.2.2。):
如果它表示所调用的函数的表达有一个类型,其包括一个原型,参数的数目应的参数的数量一致。
然而,这种限制并不适用于这种情况,因为该函数的类型不包含原型。 但这里是在语义部分(不是“约束”),这不适用随后的声明:
如果它表示所调用的函数的表达有一个类型不包括一个原型...如果参数的数量不等于参数的数量,则该行为是未定义的。
因此,函数调用并导致不确定的行为(即程序没有“严格符合”)。 然而,该标准只要求实现当实际约束被违反报告诊断消息,在这种情况下,不存在违反约束。 因此GCC不需要报告错误或警告,以成为“符合标准的实现”。
因此,我认为这个问题的答案,为什么海湾合作委员会允许它?是GCC不需要报什么,因为这不是一个约束冲突。 此外GCC不要求报告每一种未定义行为,即使-Wall或-Wpedantic。 这是不确定的行为,这意味着实现可以选择如何处理它,和gcc却偏偏编译没有警告(显然它只是忽略参数)。