歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> 為什麼C程序裡一定要寫main函數

為什麼C程序裡一定要寫main函數

日期:2017/3/1 9:07:23   编辑:Linux編程

為什麼C程序裡一定要寫main函數

一、 學習過程

編寫程序f.c:

對其進行編譯,正常通過,再對其進行連接,出現錯誤:

顯示的出錯信息為:

翻譯成中文是:在c0s模塊沒有定義符號’_main’。

那麼這個錯誤信息可能與文件c0s.obj有關。那麼是什麼原因導致編譯出錯呢?

既然已經將程序編譯成了obj文件,那麼用之前我們經常使用的link.exe能否將它連接呢?結果是可以的:

用debug查看f.exe:

程序是從06fb:0到06fb:001c,一共29個字節。但是整個程序的代碼有541字節:

執行最後一條ret指令,返回到b800處:

查看該地址的上一條指令:

發現上一條指令是push ds,不是跳轉指令,所f.exe沒有正確返回.

由上圖知f函數的偏移地址是0.

編寫程序m.c:

對m.c進行編譯連接,這一次連接沒有出現錯誤。

用debug查看m.exe,發現代碼還是在1fa處:

程序是從06fb:01fa到06fb:0216,一共29個字節。但是整個程序的代碼有4.19KB:

程序返回06fb:011d,查看該地址之前的代碼:

發現上一條指令是call 01fa,即跳轉到主程序所在代碼段,所以程序的返回是正確的。

觀察兩個程序的匯編代碼發現:

(1)f.exe的偏移地址為0,在debug中直接用u命令就可看到,而m.exe的偏移地址為1fa,在debug中用u命令查看到的不是main函數中的代碼。

(2)f.exe有沒有被調用,所以函數返回是錯誤的,m.exe被調用了,所以函數的返回是正確的。

由上圖知:對main函數進行調用的指令地址為06fb:011a,整個m.exe程序返回的指令是:

我們發現,對main函數進行調用的指令和程序返回的指令都不是我們所寫的語句,而是編譯或連接過程中提供的。

沒有main函數時,Tc裡出現連接錯誤,提示c0s.obj裡的main是沒有定義的,而沒有c0s.exe就無法對程序進行連接,那麼有可能tc是把c0s.obj或者它的一部分與m.exe

一起進行連接生成exe文件。而且對main函數進行調用的指令和程序返回的指令應該就是c0s.obj所提供的。那麼我們要對c0s.obj進行研究,可以用link.exe對它進行連接,再用debug查看匯編代碼。發現雖然link提示錯誤,但是還是生成了c0s.exe文件:

用debug查看c0s.exe和m.exe發現連個程序的代碼非常相似,那麼m.exe中調用了main函數,c0s.exe中調用了什麼呢?

可以看到,c0s.exe中本來應該指向main函數段的地方因為找不到main函數,所以指向了下一條語句。還有這兩段程序中call的程序段地址都不一樣。

所以C語言編程一定要寫main函數是因為c0s.obj連接後要調用main函數執行其功能,如果我們把main函數寫成其他的函數,c0s.obj裡的代碼不會識別。如f.exe雖然可以由link.exe連接,但是不會被調用,而是直接執行其中的內容,造成返回錯誤。而書上說c0s.obj的作用是:在程序開始運行,進行相關初始化,再調用main函數,返回後進行相關的資源釋放,環境恢復等工作,再將程序返回。那麼如果我們改寫c0s.obj使其調用的不是main函數而是其他函數,編程時就可以不寫main函數了。

編寫c0s.txt:

用masm編譯成obj文件,覆蓋原來的c0s.obj文件。

將f.c重新編譯連接,這次的連接成功了。

用debug查看f.exe:

發現我們重寫的c0s.obj的內容出現在程序中,f函數的偏移地址為0012,且返回正確。f.exe可以正確運行。

編寫新的程序f.c:

這裡的實現原理與上一篇的最後一個程序相同,不同的是將main函數換成了f函數,因為我們重寫了c0s.obj,所以同樣可以執行。但是為什麼前者是用malloc函數開辟了20個字節的空間,而後者是直接賦0呢?我覺得應為是200:0的安全空間,所以可以直接使用,但是如果在比較復雜的程序中或者空間比較緊張,則要先開辟空間,這樣比較安全。

二、 解決的問題

(1) c0s.obj文件的作用:在程序開始運行,進行相關初始化,再調用main函數,返回後進行相關的資源釋放,環境恢復等工作,再將程序返回。

(2) 可否用其他函數代替main函數?

答:可以,但是要修改c0s.obj文件。

三、 未解決的問題

(1) link.exe是集成了c0s.obj、emu.obj等所有編譯需要的文件嗎?

(2) 如果不修改c0s.obj,要將f.c編譯成功還需要哪些文件?

四、 學習感想

我們在解決復雜的問題時,要把它分解成一個一個小問題來解決。這次的研究是書上提出了問題來幫助我們理解和思考,但是真正解決問題時是沒有人來幫助我們劃分問題、提出問題的。所以在平時的學習中,我們要多督促自己養成好的思考的習慣。

Copyright © Linux教程網 All Rights Reserved