C函数定义为int但在正文中没有返回语句仍然编译

假设您有这样的C代码:

#include  int main(){ printf("Hello, world!\n"); printf("%d\n", f()); } int f(){ } 

它用gcc编译好,输出(在我的系统上)是:

你好,世界!

14

但是……但是……这怎么可能? 我认为C不会让你编译那样的东西因为f()没有返回整数的return语句。 为什么允许这样做? 它是Cfunction或编译器遗漏,14来自哪里?

在这种情况下,返回值取决于确切的平台,可能是在汇编级别的返回寄存器中发生的任何随机值(例如x86上的EAX )。 不允许显式返回值,但会给出未定义的值。

在这种情况下,14是printf的返回值。

使用-Wall编译以在编译器中启用更多的健全性检查。

 gcc -Wall /tmp/ac /tmp/ac: In function 'main': /tmp/ac:5: warning: implicit declaration of function 'f' /tmp/ac:6: warning: control reaches end of non-void function /tmp/ac: In function 'f': /tmp/ac:10: warning: control reaches end of non-void function 

注意它如何标记缺少的return语句 – 因为“控制到达非void函数的结尾”?

总是使用-Wall或类似程序进行编译 – 稍后您将为自己省心。


我可以回想一下,当这个确切的问题导致几小时或几天的调试时,我会回想起它 – 它的排序直到有一天都没有。

14也是第一个printf的返回值。 也许,编译器优化了对f()的调用,然后我们在EAX上留下了14。

尝试使用不同的优化级别(-O0,-O1,-O2,-O3,-Os)编译代码,并查看输出是否发生变化。

18是第一个打印语句的返回值。 (打印的字符数)

该值存储在堆栈存储器中。

在第二个printf函数中,堆栈值由函数f“返回”。 但是f只是将printf在堆栈中创建的值保留在堆栈中。

例如,在此代码中:

 #include  int main(){ printf("Hello, world!1234\n"); printf("%d\n", f()); } int f(){ } 

哪个用gcc编译好,输出(在我的系统上)是:

你好,世界!

18

有关printf()返回值的详细信息,请发邮件给我。

函数的默认返回值是int。 换句话说,除非明确指定,否则编译器的默认返回值将是函数的整数值。

因此,允许省略return语句,但如果您尝试使用它,则将返回未定义的值。

您可能将编译器集的警告级别设置得非常低。 因此,即使结果未定义,也允许这样做。

我用-Werror=return-type编译来防止这种情况。 如果您不从函数返回,GCC将给出错误(除非它返回无效)。