2013-05-15 111 views
3

當我忘記編寫函數的return子句時,我遇到了這個問題,但gcc中沒有任何警告或錯誤。我解決了它,但開始想知道爲什麼該函數會返回毫無意義的而沒有return。下面是一些例子我想:如果沒有明確的「返回」,函數將返回什麼

#include "stdio.h" 
#include "stdlib.h" 

int func1() { 
     int i; 
     i = 2; 
} 

int func2 (int a) { 
     int i = a+3; 
} 

int func3() { 
     int i; 
     for (i = 0; i <= 1; i++); 
} 

int main(void) { 
     int a = 0; 
     int b = 0; 
     int c = 0; 
     a = func1(); 
     printf("a = %d \n", a); 
     b = func2(a); 
     printf("b = %d \n", b); 
     c = func3(); 
     printf("c = %d \n", c); 
} 

而且結果是:

a = 1 
b = 4 
c = 7 

我的問題:

1)爲什麼這些結果?這是否有任何一般規則?
2)爲什麼要保持這個東西而不是報錯?它能在某處「某種程度上有用」嗎?

+2

好問題。我特別感興趣的是,如果有人對你的問題有一個答案,爲什麼 - 如果它沒有明確定義 - 這樣做仍然不是一個錯誤。 –

+0

@JoachimIsaksson是不是'return;'完全有效? – Thokchom

+0

如果在Visual Studio 2008及更高版本中編譯,編譯器會給出錯誤'func必須返回一個值' – Ayse

回答

5

這是undefined behavior,將取決於使用的calling convention。如果調用者期望在寄存器中得到結果,則將使用寄存器中最後一個值。

編輯

在節中的draft C99 standard6.9.1函數定義款說:

如果達到}終止函數,函數調用的值由調用者使用的 ,行爲是未定義的。

clang將默認警告和gcc將與-Wall警告,一般你應該啓用警告。

+0

而不僅僅是調用約定,例如x86上eax的最後一個值。確實非常不確定。 – jleahy

2

在我的系統(GCC 4.5.3,Linux的),編譯代碼沒有優化,我得到這個:

main: 
... 
    call func1 
    movl %eax, 28(%esp) 
... 

func1返回值是從EAX寄存器繪製,但該寄存器從未設置在func1之內,所以返回值就是該函數被調用時發生在該寄存器中的任何事情。

7

它是每節6.9.1不確定的行爲,第12(C標準的N1570草案):

如果終止的函數}達到,和函數調用的值被調用者使用,行爲是未定義的。

如果調用者未使用返回值,則行爲不是未定義的。

單純的未定義行爲不需要診斷信息,因此編譯器沒有義務發出警告。 gcc會警告你是否要求(-Wreturn-type,暗示爲-Wall),並且clang會默認發出警告。

對於返回比void之外的類型的功能,一個return語句必須包含其值的表達式應當返還,每6.8.6.4,第1段:

return語句用表達不應出現在一個返回類型爲void的函數。沒有表達式的return語句只能出現在返回類型爲void的函數中。

+0

是**返回; **有效的返回聲明? – Thokchom

+0

如果該函數聲明爲返回「void」以外的內容,則不適用。 –

+0

'6.9.1,第12段'這是從哪裏來的? –

相關問題