標籤:

c語言中int main()主函數的結尾為何有時有return 0有時沒有?


參考標準:

C11(ISO/IEC 9899:2011)

C11 5.1.2.2.3 Program termination

……如果main函數的返回值是一個與int兼容的值,那麼main函數的初始調用的返回相當於用main函數的返回值作為參數調用exit函數;到達終止main函數的}時會返回0。……

TL;DR:main函數不寫return默認返回0。

----------------分割線----------------

既然 @劉彬 提到了,那麼就補充一下不是main的情況:

C11 6.9.1 Function definitions

如果到達終止函數的},且函數調用的值被調用者使用,則行為未定義。

即使在x86中返回值的確存放在eax寄存器中,實際使用中也不應該依賴這種未定義行為。編譯器一般會扔給你一個警告,比如:

[Warning] no return statement in function returning non-void [-Wreturn-type]


以上所有答案都不完整,甚至還有錯誤的答案,

其實這種問題,試試不就知道了嗎。

寫一個test.c:

#include &
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"
.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 語句一定要寫。


有的編譯器會給你加上


return 0首先是告知程序結束,很重要的一點是輸出到標準錯誤流,表示程序執行正確。調試程序的時候可以編寫 return 1或者其他不是0的數字。表示程序執行出錯。。


不寫的話就默認return 0


寫return0的意思為函數主函數整體運行後,返回0

不寫0正常情況是不行的吧?應該為void main,表示無返回值


推薦閱讀:

C語言中case後真的不能跟範圍?
C語言里如何按需生成函數指針數組?
強制類型轉換表達式,結果是左值嗎?
sizeof(void*)的大小到底由何決定?
C++new運算符調用operator new 分配內存後, 構造函數調用及指針類型的轉換在哪裡完成?

TAG:C編程語言 |