📦 归档笔记 — 原创建于 WizNote,仅作归档展示;观点以当年为准,非最新。

关于main函数以及其他函数返回值

创建时间2018-06-16最后修改2018-06-16原位置/程序员成长之旅/C语言/笔记/字数807
目录:程序员成长之旅/C语言/笔记

若main函数没有return函数会默认返回  0  (对于main函数,编译器会自动返回0;)

若其他函数没有return 会返回上一次返回的内容(对于其他函数,返回值取决于上一次eax寄存器移入的值。)

** **

知乎链接:c语言中int main()主函数的结尾为何有时有return 0有时没有? - 刘彬的回答 - 知乎

** **

备份:

{

作者:刘彬 链接:https://www.zhihu.com/question/51597277/answer/126739598 来源:知乎 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

以上所有答案都不完整,甚至还有错误的答案, 其实这种问题,试试不就知道了吗。 写一个test.c:

#include <stdio.h> int test1(void) { return 0; } int test2(void) { return -1; } int test3(void) { } int main(void) { int a1,a2,a3; a1=test1(); a2=test2(); a3=test3(); printf("%d %d %d",a1,a2,a3); }

编译一下,不要优化

gcc -S -O0 test.c

得到一个test.s :

.file "test.c" .text .globl test1 .def test1; .scl 2; .type 32; .endef .seh_proc test1 test1: pushq %rbp .seh_pushreg %rbp movq %rsp, %rbp .seh_setframe %rbp, 0 .seh_endprologue movl $0, %eax popq %rbp ret .seh_endproc .globl test2 .def test2; .scl 2; .type 32; .endef .seh_proc test2 test2: pushq %rbp .seh_pushreg %rbp movq %rsp, %rbp .seh_setframe %rbp, 0 .seh_endprologue movl $-1, %eax popq %rbp ret .seh_endproc .globl test3 .def test3; .scl 2; .type 32; .endef .seh_proc test3 test3: pushq %rbp .seh_pushreg %rbp movq %rsp, %rbp .seh_setframe %rbp, 0 .seh_endprologue nop popq %rbp ret .seh_endproc .def __main; .scl 2; .type 32; .endef .section .rdata,"dr" .LC0: .ascii "%d %d %d\0" .text .globl main .def main; .scl 2; .type 32; .endef .seh_proc main main: pushq %rbp .seh_pushreg %rbp movq %rsp, %rbp .seh_setframe %rbp, 0 subq $48, %rsp .seh_stackalloc 48 .seh_endprologue call __main call test1 movl %eax, -4(%rbp) call test2 movl %eax, -8(%rbp) call test3 movl %eax, -12(%rbp) movl -12(%rbp), %ecx movl -8(%rbp), %edx movl -4(%rbp), %eax movl %ecx, %r9d movl %edx, %r8d movl %eax, %edx leaq .LC0(%rip), %rcx call printf movl $0, %eax addq $48, %rsp popq %rbp ret .seh_endproc .ident "GCC: (tdm64-1) 5.1.0" .def printf; .scl 2; .type 32; .endef

其中rbp寄存器是帧指针,eax寄存器用于返回值。 其中 test1 ,test2,帧指针出栈前会把返回值放入eax中,例如 test1的情况

movl $0, %eax

eax寄存器是要求调用者保存的寄存器,也就是说函数返回时,eax是不会出栈的。 注意到test3中没有这条指令,也就是说test3函数没有对eax寄存器的操作,那么返回值取决于上一次对eax寄存器的操作。 有意思的是main函数,虽然也没有return语句,但在返回前有一条指令把eax设为0了,也就是编译器自动设置返回0。

运行一下试试

gcc -o test -O0 test.c

运行结果为 0 -1 -1,大家可以自己试一下。 也就是说test3返回了-1,实际上就是上一次test返回时eax寄存器移入的值。 结论: 对于main函数,编译器会自动返回0; 对于其他函数,返回值取决于上一次eax寄存器移入的值。

对了,以上结论只是在x86体系中,gcc编译器,而且优化为O0的结果。另外@SuperSodaSea 提到标准中普通函数中这种做法是未定义行为。所以实际项目中普通函数的return 语句一定要写。

** **

}

** **