有人知道为什么this在C中成功编译?
int main(){
display();
return 0;
}
void display(){
printf("Why am I compiling successfully?");
}
我认为当没有提供声明时C假设extern int Function_name(arg1,arg2,...){}.
因此这应该给出一个错误但是它有效!我知道Ideone正在压制警告,但我的问题是为什么它不是直接错误? (但在C ++中它是直接的错误)
答案 0 :(得分:8)
调高编译器中的警告级别,您应该收到2次警告,
display
未声明,int
假设
和
display
已重新宣布
修改强>
旧版本的C(前C99)并没有真正对返回类型或参数类型感到困扰。你可以说这是K& R遗产的一部分。例如,如果您没有显式指定参数类型,编译器将根本不检查它们。
C ++更严格,IMO是一件好事。我总是提供声明,并且在用C编码时总是指定参数列表。
答案 1 :(得分:5)
它正在编译,因为C使用许多默认值向后兼容。在K& R C中,您无法指定函数原型,因此编译器只会假设您在调用函数时知道自己在做什么。
后来(至少是ANSI C,但也许在C99中),C真的没有办法区分
void display(void);
void display();
所以也必须接受空声明。
这就是为什么你可以先调用display()
而不先定义它。
printf()
类似。如果忘记-lc
,将会收到链接器错误,但从编译器的角度来看,代码“足够好”。
一旦启用编译器必须提供的所有警告,它就会改变,当您禁用K& C兼容性或启用严格的ANSI检查时,它将失败并显示错误。
这就是“C”在“How to Shoot Yourself In the Foot Using Any Programming Language”列表中经常被列为“你射到脚下”的原因。
答案 2 :(得分:3)
取决于您的Cx(C89,C90,C99,...)
对于函数返回值,在C99之前明确规定如果没有可见的函数声明,则转换器提供一个。这些隐式声明默认为返回类型int
来自C Standard的理由(6.2.5第506页)
在C90之前,没有功能原型。开发人员期望 能够互换签名和未签名的论点 相同整数类型的版本。必须施展论据,如果 函数定义中的参数类型具有不同的符号, 被视为与C的易于进行的类型检查系统和a 很少侵入性的。原型的引入并没有完全发挥作用 远离论证的可互换性问题。省略号 符号规定没有人知道1590省略号 提供没有信息的预期参数类型。同样,为 函数返回值,在C99之前明确指定了 如果没有看到功能声明,则翻译提供一个。 这些隐式声明默认为返回类型的int。如果 实际的函数碰巧返回类型unsigned int,这样的 默认声明可能返回了意外的结果。许多 开发人员对功能声明有一种随意的态度。该 我们其他人不得不忍受委员会的后果 想要打破他们写的所有源代码。该 函数返回值的可互换性现在是一个有争议的问题, 因为C99要求在...处显示函数声明 调用点(不再提供默认声明)
答案 3 :(得分:1)
它可能会(假设你写的这样的声明),但由于你没有传递参数,它只是工作正常。如果您声明int main()
实际应该是int main(int argc, char *argv[])
,那就相同。
因此,如果您尝试从main
传递一些参数(与默认参数不同),那么可能会在display
中使用它们会失败。
$ gcc z.c
z.c:8:6: warning: conflicting types for ‘display’ [enabled by default]
z.c:4:5: note: previous implicit declaration of ‘display’ was here
答案 4 :(得分:0)
当我使用gcc编译时,我会收到关于display
重新声明的警告,正如您所期望的那样。
你收到了警告吗?
它可能会“运行”,因为C不会破坏函数名称(如C ++)。因此链接器会查找符号'display'并找到一个符号。链接器使用此地址运行display
。我希望结果不会像你期望的那样。