C 語言中 int main() 和 void main() 有何區別?

第一次接觸 C 語言,嚴格的說,是第一次接觸計算機程序設計語言。第一堂課就是這個 Hello,world! 程序,第二節課是 int, void 等等了,我自己就去敲代碼了,用了 void main(),我是第一個寫出程序運行正確並上交的(班級領頭羊已經不管這種小兒科了,自己學到後面了),很驕傲,交上去馬上得到,老師一頓訓,非要說我寫 void main 是錯的,要我改成 int main 加上 return 0; 雖然現在已經習慣使用 int main,但是,一直不知道區別。誰來解釋解釋區別?


搬運一下自己博客的文章: main原型考證及程序終止行為

在C和C++中流傳著很多版本的main函數聲明,不同的書里也有不同的寫法。今天我從幾種標準(C89/99/11以及C++98/03/11/14)的角度來尋找一下什麼是「標準行為」以及在主函數中return後發生了什麼。

比較常見的是下面幾種:

void main()
main()
int main()
int main(void)
int main(int argc,char *argv[])

void main()

首先,從標準角度(所有版本)來說,void main()肯定是錯的,沒有任何標準(C89/99/11以及C++98/03/11/14)中允許過這種寫法。

但是我在APUE里看到了一種把主函數寫為void main()的原因,不知道是不是有人從這個角度說的然後就以訛傳訛了。

The problem is that these compilers don』t know that an exit from main is the same as a return. One way around these warnings, which become annoying after a while, is to use return instead of exit from main. But doing this prevents us from using the UNIX System』s grep utility to locate all calls to exit from a program. Another solution is to declare main as returning void, instead of int, and continue calling exit. This gets rid of the compiler warning but doesn』t look right (especially in a programming text), and can generate other compiler warnings, since the return type of main is supposed to be a signed integer.

評論區 @James Swineson 提到了另一種可能:

void main 的寫法可能是從嵌入式來的……沒有操作系統,入口點是硬體實現,返回任何東西都沒意義 。

main()

在KR C與C89里,函數沒有顯式聲明返回類型,則默認是int:

C89對函數定義的語法(Syntax)描述如下(注意declaration-specifiersopt下標符號):

$$declaration specifiers{opt}hspace{2mm}declaratorhspace{2mm}declaration list{opt}hspace{2mm}compound statement$$

C89中declaration-specifiersSyntax上為:

  • storage-class-specifier
  • type-specifier
  • type-qualifier

表明在C89中函數的return type可以省略。

KR C里的描述如下:

Various parts may be absent; a minimal function is

dummy() {}

which does nothing and returns nothing. A do-nothing function like this is sometimes useful as a place holder during program development. If the return type is omitted, int is assumed.

所以說:

func(){}
// 等價於
int func(){}

但是這種方式在C99之後就被廢除掉了(注意declaration-specifiers沒有opt下標了):

[Math Processing Error]declaration.specifiersdeclaratordeclaration.listoptcompound.statement

綜上,在C89中,函數的返回類型可以省略,但默認為int,即

主函數聲明main()隱式是int main()。

int main()

int main()和int main(void)在C語言中是有區別的:

int main()
// 不等價於
int main(void)

在C語言中參數列表為空(即不提供參數列表也不為void),表示不提供參數數量和參數類型信息:

int func(){
print("func()
");
return 0;
}
int main(void){
func(1,2,3,4);// call func();
}

The empty list in a function declarator that is not part of a definition of that function specifies that no information about the number or types of theparameters is supplied.

C99/11 Standard

在C99/11標準中,明確定義了對於標準的main函數的兩個原型:

The function called at program startup is named main. The implementation declares no prototype for this function. It shall be defined with a return type of int and with no parameters:

int main(void) { /* ... */ }

or with two parameters (referred to here as argc and argv, though any names may be used, as they are local to the function in which they are declared):

int main(int argc, char *argv[]) { /* ... */ }

or equivalent;or in some other implementation-defined manner.
If they are declared, the parameters to the main function shall obey the following constraints:

  • The value of argc shall be nonnegative.
  • argv[argc] shall be a null pointer.
  • If the value of argc is greater than zero, the array members argv[0] through argv[argc-1] inclusive shall contain pointers to strings, which are given implementation-defined values by the host environment prior to program startup. The intent is to supply to the program information determined prior to program startup from elsewhere in the hosted environment. If the host environment is not capable of supplying strings with letters in both uppercase and lowercase, the implementation shall ensure that the strings are received in lowercase.
  • If the value of argc is greater than zero, the string pointed to by argv[0]
    represents the program name; argv[0][0] shall be the null character if the program name is not available from the host environment. If the value of argc is greater than one, the strings pointed to by argv[1] through argv[argc-1]
    represent the program parameters.
  • The parameters argc and argv and the strings pointed to by the argv array shall be modifiable by the program, and retain their last-stored values between program startup and program termination.

C++ Standard

由於C和C++中對於函數參數列表的規則並不一致(C++中參數列表為空代表不接收任何參數)。所以C++中main的原型和ISO C也並不太一樣:

  • a function of () returning int and
  • a function of (int, pointer to pointer to char) returning int

main return value

main必須要有返回值的原因是:在C和C++中使用return-statement都是將return的值作為參數來調用exit/std::exit來終止程序。

If status is zero or EXIT_SUCCESS, an implementation-defined form of the status successful termination is returned.

ISO C99/11:
If the return type of the main function is a type compatible with int, a return from the initial call to the main function is equivalent to calling the exit function with the value returned by the main function as its argument;reaching the } that terminates the main function returns a value of 0. If the return type is not compatible with int, the termination status returned to the host environment is unspecified.

ISO C++11/14:
A return statement in main has the e?ect of leaving the main function (destroying any objects with automatic storage duration) and calling std::exit with the return value as the argument. If control reaches the end of main without encountering a return statement, the e?ect is that of executing

return 0;

exit

#include &

The exit function causes normal program termination to occur. If more than one call to the exit function is executed by a program, the behavior is undefined.

  • First, all functions registered by the atexit function are called, in the reverse order of their registration,except that a function is called after any previously registered functions that had already been called at the time it was registered. If, during the call to any such function, a call to the longjmp function is made that would terminate the call to the registered function, the behavior is undefined.
  • Next, all open streams with unwritten buffered data are ?ushed, all open streams are closed, and all files created by the tmpfile function are removed.
  • Finally, control is returned to the host environment. If the value of status is zero or EXIT_SUCCESS, an implementation-defined form of the status successful termination is returned. If the value of status is EXIT_FAILURE, an implementation-defined form of the status unsuccessful termination is returned. Otherwise the status returned is implementation-defined.
  • Next, all open streams with unwritten buffered data are ?ushed, all open streams are closed, and all files created by the tmpfile function are removed.
  • Finally, control is returned to the host environment. If the value of status is zero or EXIT_SUCCESS, an implementation-defined form of the status successful termination is returned. If the value of status is EXIT_FAILURE, an implementation-defined form of the status unsuccessful termination is returned. Otherwise the status returned is implementation-defined., an implementation-defined form of the status unsuccessful termination is returned. Otherwise the status returned is implementation-defined.

The exit function cannot return to its caller.

_Exit

#include &
void _Exit(int status);

The _Exit function causes normal program termination to occur and control to be returned to the host environment. No functions registered by the atexit function or signal handlers registered by the signal function are called. The status returned to the host environment is determined in the same way as for the exit function (7.20.4.3).Whether open streams with unwritten buffered data are ?ushed, open streams are closed,or temporary files are removed is implementation-defined.
The _Exit function cannot return to its caller.

http://7xilo9.com1.z0.glb.clouddn.com/blog-images/others/StartAndterminatesACProgram.png


@SuperSodaSea 在評論中提到,main是個特例(which I didn"t notice in the first place), 5.1.2.2.3 #1,

非常感謝。

----

原答案:

Yutong Zhang, on behalf of the ISO/IEC commitee.

這個時候應該引用ISO/IEC 9899:1999文檔(或是ISO/IEC 9899:2011,取決於你學的是哪個版本的C語言)(Programming languages -- C)的5.1.2.2.1 #1,(由於我沒有找到免費的2011的文檔,所以用Google上的第一個關於ISO/IEC 9899:1999的免費結果……)

以及同文檔的6.9.1 #12……

5.1.2.2.1 #1提到「......or in some other implementation-defined manner」,所以你的編譯器或許也提供了其它的program startup給你,但是只要是符合標準的編譯器,一定會有這裡說明的兩種startup。

而6.9.1 #12則提到了「If the } that terminates a function is reached, and the value of the function call is used by the caller, the behavior is undefined.」,所以不寫return是真的undefined behavior。

終於,我也成為了語言律師呢!下次來個C++的,哦,順便去讀讀Haskell Report 2010吧……


考證什麼的上面很多回答都說了,簡單總結就是,main有兩種形式:

int main(void); //在C++中,這個void可以省略不寫

int main(int argc, char *argv[]);

這方面你老師說的是對的

但是最後的return 0,是可以省略的,main最後如果沒有return,則會自動return 0,但是記住,只有main函數是這樣,其他函數不能省略return

main返回值寫成void在很多時候也能編譯通過,實際上你還能碰到一些奇奇怪怪的代碼也能編譯通過,比如main根本不實現為函數的情況,直接寫:

char main[] = {1,2,3,4,...};

數組初始化的值我是亂寫的,如果你仔細賦值為正確的機器碼,在大部分環境下也能編譯通過並運行,這是利用了很多連接器在連接obj文件的時候按名字查找的做法,但是,這種做法用標準的話說,不按上面的規定格式聲明的main函數,是ill-formed的代碼,別這麼玩,老實一點比較好


int main是標準規定,可以說沒有為什麼,就這麼規定的

當然往細了說,是操作系統需要檢查main的返回值,來判斷程序是不是正確退出。


看起來你遇到了一個好老師……

為什麼主函數用int main()比用void main()好?

C11 5.1.2.2.1 程序啟動

return 0 倒不是必須的:

C11 5.1.2.2.3 程序終止

不過你加上也沒問題。


謝邀

高票答案已經說的挺詳細了,我做一點補充

首先,main函數是由系統調用的,系統就是這樣調用這個函數的,你這個函數原型就必須得這樣寫。

C語言函數如果沒有指定返回值類型則默認是int,cpp會報錯

C語言函數沒有顯式指明參數,默認支持任意類型的參數(...),cpp則默認不支持任何參數輸入(void)

主函數默認返回零,有些編譯器其它函數也默認返回零。

所以你寫的一些原型,編譯器是承認的,比如C中的

main(){}

但是寫好是一個習慣,最好寫成

int main(int argc, char*argv[]){return 0;}

保證任何版本都不會出錯,而且別人維護也方便


主函數返回值為整型是規定(C99)。為什麼返回的數為什麼非要是0呢,我記得返回0表示這個程序運行正確,返回值!0說明出問題了。
有的書上(國內C語言紅寶書),主函數返回類型用空,按規定是錯的,有些編譯器根本就不認(比如GCC)

OK~that~

感覺被打臉了~

後來手動加上c99的支持~

~上次給學弟們演(zhuang)示(bi)還不是這個樣子的~~~

@Salted Filsh 大牛快救我~~~

不過在開發單片機的時候,好多IDE用的並不是標準的C語言編譯器,所以開發單片機用void沒問題~~


C語言規範中不存在void main,main函數的返回值必須是int


寫這個答案主要是為了自己複習一遍加深記憶。

C的標準:main函數默認返回類型為int,預設return 0語句。

所以C的main最簡單寫法是main(void)。

C++的標準:函數參數列表為空則默認為void,預設return 0語句。

所以C++的main最簡單寫法是int main()。

至於C裡面「著名」的void main(),是一個不符合標準但又可以在一堆環境下通過的寫法,不被推薦。


在linux中,每個指令執行完都會有一個返回值保存在?變數中,可以在腳本中判斷上一條指令執行是否成功,而這個返回值就是通過main函數的return 0返回的。當然,void main 也不會報錯。


C語言程序在編譯階段,main函數與編譯器提供的一些分配資源的函數鏈接在一起,程序裝入內存後,由這些函數完成分配系統資源,初始化棧堆等操作,然後調用main函數,完成程序功能。也就是說main函數在這裡和其他我們調用的函數並無區別,所以int main函數返回整數值,如果main函數返回非0值,就會被調用main函數的函數當做錯誤代碼,進行一些相關處理。


c語言發明者寫的c語言教程反覆強調void main是錯的。

但編譯器其實是可以通過的。

比如int n=5;
int a[n];語法是錯誤的

但你的編譯器是C99標準就可以通過


int main()可以通過return的結果來確定程序的運行狀態


因為有時要判斷一個程序是否運行成功,是通過它的返回值


用不上返回值的話void也行啊。當然優先按長者的要求辦。


void main表示函數沒有返回值,而main則有返回值。只不過給省略了而已!函數沒有聲明類型時默認是為整型的,main等同於int main 。自定義函數時如果主函數用的是void main,就不能使用return把值返回給主函數,會報錯


推薦閱讀:

能否寫出一個程序,按照需求,自動生成實現的代碼?
Brian W. Kernighan和Dennis M. Ritchie當年用什麼軟體寫出了《The C Programming Language》?
任何遞歸程序都能轉換為一個等價的非遞歸程序嗎?
把函數式編程語言寫得和彙編一樣是一番怎樣的感受?
Mathematica中如何定義f[x+y]=f[x]+f[y]?

TAG:編程 | C編程語言 | C | CC |