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将给出错误(除非它返回无效)。