背景簡介
本文是前段在知乎回答的一個問題,覺得蠻重要的,重新編撰發佈如下。
原問題為:
"c語言中,如果main函數的末尾沒有return語句將會有什麼影響?":
我是準大一,學計算機的,剛剛接觸計算機,萌新求解答
原回答請參考這裡: https://www.zhihu.com/question/338814178/answer/785578903。
問題的本質
回答這個問題其實只要理解一個東西就行了:
那就是帶有返回值的函數請務必提供返回值,這個是基本約定也是編程習慣,如果大家都遵守,你不遵守,各種奇葩和頭疼的後果就遲早會來,不管是 main 也好,其他函數也好。
所以,準大一這個時候一定要從現在開始養成習慣,遵守語言的基本約定。
int main(int argc, char *argv[])
很多同學寫例子,也有這麼寫的?
void main(void) { }
實際上,完整的 main 聲明還有第三個參數 env,這裡不做展開。
C 語言各標準差異以及靜態檢測方法
這種可以用 -Wall 檢查出來:
$ echo 'void main(void) {}' | gcc -Wall -x c - -
<stdin>:1:6: warning: return type of ‘main’ is not ‘int’ [-Wmain]
/<stdin>
如果用 int 默認檢查不出來 return value ,默認是兼容 c11 的 gnu11:
$ echo 'int main(void) {}' | gcc -Wall -x c - -
$ echo 'int main(void) {}' | gcc -Wall -std=gnu11 -x c - -
試了下,c99 之後都是沒有提示問題。但是 c90 以及之前都提示需要加返回值:
$ echo 'int main(void) {}' | gcc -Wall -std=c90 -x c - -
<stdin>: In function ‘main’:
<stdin>:1:1: warning: control reaches end of non-void function [-Wreturn-type]
/<stdin>/<stdin>
考慮到兼容性,建議務必養成寫法上的習慣。由於 main 稍微特殊些,c99 默認處理了,但是對於其他函數還是要自己加,不做處理的話,是有很大風險的。
對於 c99 以及之後的版本,對普通函數還是會做檢查。如果有的寫,有的不寫,不一致的話久而久之習慣就很難養成了。
$ echo 'int test(void) {}; int main(void) { test(); }' | gcc -Wall -std=c99 -x c - -
<stdin>: In function ‘test’:
<stdin>:1:1: warning: control reaches end of non-void function [-Wreturn-type]
/<stdin>/<stdin>
由於人總會出錯,所以,在編譯的 cflags 裡頭,建議強制加上 -Wall -Werror,在遇到這類錯誤是強制退出,而不僅僅是警告。當然,對於已經存在的項目,prove-in-use 的情況下,建議保留之前的默認配置選項,除非要確實投入很多精力去重構。
$ echo 'int main(void) {}' | gcc -Wall -Werror -std=c90 -x c - -
<stdin>: In function ‘main’:
<stdin>:1:1: error: control reaches end of non-void function [-Werror=return-type]
cc1: all warnings being treated as errors
/<stdin>/<stdin>
關於返回值的含義
需要注意的是,默認情況下,沒有錯誤,就是 return 0,而不是 return 1。
完整的模板:
int main(int argc, char *argv[])
{
return 0;
}
上面多次提到了後果和風險,為什麼?因為檢查函數和程序返回值是一個最最基礎的操作。如果不按常理返回正確的返回值,後果是,後續對該值的檢查所做出的所有動作都可能不可預知。
這個值是怎麼體現的呢?
$ echo -e 'int main(void){ return 0; }' | gcc -Wall -Werror -std=c99 -O0 -x c - -
$ ./a.out
$ echo $?
0
$ echo -e 'int main(void){ return 100; }' | gcc -Wall -Werror -std=c99 -O0 -x c - -
$ ./a.out
$ echo $?
100
比如說,在 Shell 編程中通常會在程序執行完,立即檢查返回值,然後決定接下去做什麼操作?
if [ $? -eq 0 ]; then echo 'Success'; else echo 'Failure'; fi
閱讀更多 linux內核 的文章