郭妍
C和C++可以說是所有編程語言中關(guān)系最為緊密的兩個。在目標上,C++被定位為“a better C”;在名稱上,C++有一個別名叫做“C with classes”;在語法上,C更是C++的一個子集,C++幾乎支持C語言的全部功能。如何優(yōu)化C++程序代碼,在多年的教學經(jīng)驗中,我認為有一種方法,即不要讓main函數(shù)返回void。
同C程序一樣,每個C++程序都包含一個或多個函數(shù),而且必須有一個函數(shù)命名為main,并且每個函數(shù)都由具有一定功能的語句序列組成。操作系統(tǒng)將main作為程序入口,調(diào)用main函數(shù)執(zhí)行程序;main函數(shù)執(zhí)行其語句序列,并返回一個值給操作系統(tǒng)。在大多數(shù)系統(tǒng)中,main函數(shù)的返回值用于說明程序的退出狀態(tài)。如果返回0,則代表main函數(shù)成功執(zhí)行完畢,程序正常退出,否則代表程序異常退出。
然而在編寫C++程序入口函數(shù)main的時候,很多程序員,特別是一些具有C基礎(chǔ)的C++程序員時經(jīng)常會寫出如下格式的main函數(shù):
1.void main()
2.{
3.// some code... }
上述代碼在VC++中是可以正確編譯、鏈接、執(zhí)行的。編譯信息如下所示:
1. 1>------ 已啟動生成: 項目: MainCpp, 配置: Debug Win32 ------
2. 1>main.cpp
3. 1>MainCpp.vcxproj -> G:\MainCpp\Debug\MainCpp.exe
========== 生成: 成功1 個,失敗 0 個,最新 0 個,跳過 0 個==========
但是當你將代碼放在Linux環(huán)境下,采用GCC編譯器進行編譯時,你會吃驚地發(fā)現(xiàn)編譯器拋出了如下錯誤信息:
1.[develop@localhost ~]g++ main.cpp
main.cpp:2: 錯誤 :′::main′必須返回′int′
為什么同樣的代碼會出現(xiàn)兩種不同的結(jié)果呢?這還是跨平臺的C/C++語言嗎?不要對C/C++的跨平臺性產(chǎn)生質(zhì)疑,之所以會這樣,在很大程度上要歸咎于市面上一些書的“誤導”,以及微軟對VC++編譯器main返回值問題的縱容。 在C和C++中,不接收任何參數(shù)也不返回任何信息的函數(shù)原型為“void f(void);”,所以很多人認為,不需要程序返回值時可以把main函數(shù)定義成void main(void),然而這種想法是非常錯誤的。有一點必須明確:C/C++標準從來沒有定義過void main()這樣的代碼形式。C++之父 Bjarne Stroustrup 在他的主頁FAQ 中明確地寫著這樣一句話:“在C++中絕對沒有出現(xiàn)過void main(){/* ... */}這樣的函數(shù)定義,在C語言中也是?!?/p>
main函數(shù)的返回值應該定義為int類型,在C和C++標準中都是這樣規(guī)定的。在C99標準中規(guī)定,只有以下兩種定義方式是正確的:
1.int main( void )
2. int main( int argc, char *argv[] )
在C++03中也給出了如下兩種main函數(shù)的定義方式:
1.int main()
2.int main( int argc, char *argv[] )
雖然C和C++標準并不支持void main(),但在部分編譯器中void main()依舊是可以通過編譯并執(zhí)行的,比如微軟的VC++。由于微軟產(chǎn)品的市場占有率與影響力很大,因此在某種程度上加劇了這種不良習慣的蔓延。不過,并非所有的編譯器都支持void main(),gcc就站在了VC++的對立面,它是這一不良習氣的堅定抵制者,它會在編譯時就明確地給出一個錯誤。
如果你堅持在某些編譯器中使用void main()這種非標準形式的代碼,那么當你把程序從一個編譯器移植到另一個編譯器時,你就要對可能出現(xiàn)的錯誤負責。除了有void main()這樣的不規(guī)范格式外,在C語言程序中,尤其是一些老版本的C代碼中,你還會經(jīng)常看到main()這樣的代碼形式。
一些老的C標準(諸如C90)是支持main()這樣的形式的。之所以支持,是因為在第一版的C語言中只有int一種數(shù)據(jù)類型,并不存在char、long、float、double等這些內(nèi)置數(shù)據(jù)類型。既然只有int一種類型,也就不必顯式地為main函數(shù)標明返回類型了。在Brian W.Kernighan和Dennis M.Ritchie的經(jīng)典巨著The C Programming Language,Second Edition中用的就是main()。后來,在C語言的改進版中數(shù)據(jù)類型得到了擴充,為了能兼容以前的代碼,標準委員會就做出了如下規(guī)定:不明確標明返回值的,默認返回值為int。在C99標準中,則要求編譯器對于main()這種用法至少要拋出一個警告。
main函數(shù)返回值的作用,可以采用下面的方法加以驗證。
首先,編寫main.cpp文件,文件內(nèi)容如下所示:
1.int main()
2.{
3. return 0;
4.}
在Linux環(huán)境下,采用命令:g++ main.cpp
生成可執(zhí)行文件a.out。然后,執(zhí)行命令:./a.out && ehco “success”
結(jié)果輸出success。
修改上述程序:
1.int main( )
2.{
3.return -1;
4.}
做同樣測試,無輸出。
命令A && B中的&&類似于C++中的并操作(&&),如果A命令正確執(zhí)行,接著就會執(zhí)行命令B;如果A出現(xiàn)異常,則B不執(zhí)行。通過以上分析可知,當main()返回0時,a.out正確執(zhí)行并返回;但是如果返回-1,程序就不能正常返回了。
最后,還要說明C++標準中一個“好壞難定”的規(guī)定:在main函數(shù)中,return語句的作用在于離開main函數(shù)(析構(gòu)掉所有具有動態(tài)生存時間的對象),并將其返回值作為參數(shù)調(diào)用exit函數(shù)。如果函數(shù)執(zhí)行到結(jié)尾而沒有遇到return語句,則其效果等同于執(zhí)行了return 0。
也就是說,如果函數(shù)執(zhí)行到main結(jié)束處時沒有遇到return語句,編譯器就會隱式地為你加上return 0;,效果與返回0相同。之所以說這條規(guī)定“好壞難定”,一方面是因為它讓你省去了多敲幾個字的麻煩,另一方面是因為這種便捷會讓某些程序員忽視編譯器代替他做的工作,而在思維中形成一種錯誤的認識:此函數(shù)可以無返回。
在應用這一規(guī)則時,需要注意以下兩點:
(1)main函數(shù)的返回類型是int,不是void或其他類型。
(2)該規(guī)則僅僅對main函數(shù)適用。
按照以上標準得到了一個完全合乎C/C++標準的最小化的完整C++程int main(){} 要想保證程序具有良好的可移植性能,就要標明main函數(shù)返回int,而不是void。