c語言中的main函式討論

2021-07-29 09:30:36 字數 3143 閱讀 2222

**從剛開始寫c程式,相比大家便開始寫main()了。雖然無數的教科書和老師告訴我們main是程式的入口。那麼main函式是怎麼被呼叫的,怎麼傳入引數,返回的內容到**了,返回的內容是什麼?接下來我們來**一下這個問題。**
main()函式的形式

早期教材這麼寫:void main(){}

其實翻翻c/c++標準,從來沒有定義過void main(),使用標準的編譯器都會產生乙個警告資訊,而老師又教會我們,警告不用理會,我們只要關注錯誤即可,而c標準中main的定義只有兩種:

int main(void)

int main(int argc, char *argv)

在c++標準中main的定義也只有兩種:

int main( )

int main(int argc, char *argv)

前者表明不需要函式的引數時,使用(void)形式,如果需要引數,還是使用(int argc, char *argv),但是實際使用時,我也會使用(int argc, char *argv)這種形式,與不同平台和編譯器有關而以,在unix-like平台上,也可以int main(int argc, char *argv, char *envp),後面需要再討論。

main()函式的返回

int表明main()需要return乙個int值,如果不寫,有的編譯器會自動幫你新增乙個return 0;,而有的則會返回乙個隨機值。為了避免不必要的問題,建議寫的時候還是加上乙個return 0。

乙個簡單而又完整的test.c檔案如下:

int main(int argc, char *argv)

當然我們也可以嘗試著讓main返回乙個long, double甚至是struct,更改main函式中的形參定義。這在有些編譯器上是能編譯通過的,不過可能會有一些警告(如gcc)。但是執行的時候如果編譯器能做轉換的還好,如返回long,float. 如果不能的話(如返回struct,或者main(int argc, char *argv0,char *argv1,char *argv2))會造成segmentation fault。

main()的被呼叫

接下來看main函式是怎麼被呼叫的,它又」return」給了誰。在」gcc的編譯過程」一中,我們回顧了程式從原始碼到可執行程式的過程,在」應用程式在linux上是如何被執行的」一文中,我們回顧了可執行檔案怎麼被作業系統載入的,今天我們繼續這個過程。

上文提到不管是在load_elf_binary()中或者使用了動態鏈結庫,最後都執行到了應用程式的入口。不過這個入口不是main.而是_start()。

執行 gcc -o test test.c

readelf -a test

可以看到test檔案的entry point address是0x80482e0,在往後看,這個位址是.text的位址(**段的開始),也是_start()的位址。在_start()中又會呼叫__libc_start_main(),主要做一些程式的初始化工作,感興趣的同學可以讀讀glibc中的原始碼,注釋很清楚。然後主角登場了,在__libc_start_main()中最後會呼叫

int result = main (argc, argv, __environ main_auxvec_param);//這是unix-like下main函式的呼叫方式,這下大家明白main函式中形參的由來了吧。

result中放著main函式的返回值,然後帶著這個值退出。

exit (result);

注意:雖然main函式是乙個特殊的函式,是程式執行的入口,但它畢竟也是乙個函式,是可以被呼叫的。如:

int main()

不過要小心呼叫方式,和退出條件,避免無窮遞迴。

shell中執行程式

通過前幾次和上面的分析,我們終於基本弄清了應用程式的執行過程,再回顧一遍: 在某個互動式shell中敲入./test, 此shell fork()/clone()出乙個子程序,這個子程序執行

execve(「./test」,char * const argv, char * const envp)

execve載入./test,並把引數argv,envp一步一步傳遞下去。載入了./test之後,從./test的入口開始執行,即elf檔案中的_start(),_start()呼叫__libc_start_main(),最後到了main。

int main(int argc, char *argv, char *envp)

看著這個main的定義和execve相似吧,沒錯main中的引數都是execve一步步傳遞下來的。argc是命令列引數個數,argv儲存著各個引數的指標(注意argv[0]通常是程式名,argv[1]開始才是命令列引數。這是由shell設定的),envp儲存著環境變數表。然而在標準c中只定義了int main(int argc, char *argv),所以unix-like平台也提供了全域性變數environ指向環境變數表。

extern char **environ;

當然也可以用getenv和putenv來訪問特定的環境變數。

對了,父shell還在wait()./test的結束呢,不錯,test中main函式return的值,在被__libc_start_main() exit之後,終於被父shell抓住了,可以用?訪

問。如 > ./test

>ec

ho?

可以得到test返回的值。這樣,你就知道main()函式中return的意義,以及如何在shell中使用了吧。儘管可以return任何值,也建議用return 0來表示程式正常結束。這樣別人用shell指令碼呼叫你寫的程式的時候,就可以$?等於0來判斷你的程式是否正常執行了。

最後小結一下:

1. 避免使用void main(),盡量使用int main() 或者 int main(int argc, char *argv)。

2. 在main的結尾記得 return int;, 最好用return 0;表示程式的正常結束。

3. main函式和普通函式一樣也是能被呼叫的。

4. main return的值最終會返回給其呼叫者,如shell中執行的程式,可以在shell中用$?得到其返回值。

5. 在unix-like環境中,可以使用int main(int argc, char *argv, char *envp), extern char **environ; , getenv()等方式來得到環境變數。

C語言中main函式的引數

我們經常用的main函式都是不帶引數的。因此main 後的括號都是空括號。實際上,main函式可以帶引數,這個引數可以認為是 main函式的形式引數。語言規定main函式的引數只能有兩個,習慣上這兩個引數寫為argc和argv。因此,main函式的函式頭可寫為 main argc,argv 語言還規...

C語言中main函式的引數

我們經常用的main函式都是不帶引數的。因此main 後的括號都是空括號。實際上,main函式可以帶引數,這個引數可以認為是 main函式的形式引數。語言規定main函式的引數只能有兩個,習慣上這兩個引數寫為argc和argv。因此,main函式的函式頭可寫為 main argc,argv 語言還規...

C語言中main函式的引數

今天在嵌入式課程學習時發現一些c語言程式的main函式存在引數,針對這一問題我查詢了一些資料,整理了一下。main函式主要有這種形式 main int argc,char args 主要在liunx系統中使用命令讀取檔案資訊時用到,在dos中也有著同樣的用處。在一些編譯器允許將main 的返回型別宣...