程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> 深入研究C語言 第三篇,深入研究c第三篇

深入研究C語言 第三篇,深入研究c第三篇

編輯:關於C語言

深入研究C語言 第三篇,深入研究c第三篇


本篇研究TC2.0下其他幾個工具。同時看看TC由源代碼到exe程序的過程。

1. 用TCC將下面的程序編為.obj文件

clip_image001[4]

我們知道,TCC在默認的編譯連接一個C語言的源程序a.c的時候分為以下兩步:

(1).TCC將源程序文件編譯成a.obj。

(2).TCC調用TLINK將c0s.obj,cs.lib,emu.lib,maths.lib中的a.obj中的程序要用到的代碼與a.obj的代連接到一起生成.exe文件。

並且,我們還知道,TCC可選參數有如下:

clip_image003[4]

我們看到有這樣的選項:Compile only(只編譯)。這應該是只編譯生成.obj文件的選項。我們驗證如下:

clip_image005[4]

我們看到,文件夾下確實只生成了.obj文件:

clip_image006[4]

2.用C:\C\tcc a.c的方法編譯下面程序:

clip_image007[4]

我們看源程序,很明顯的沒有定義和實現f函數。我們看編譯連接過程中的錯誤提示:

clip_image009[4]

如我們所料,這裡出現了錯誤提示:在a.c中沒有發現f函數。

我們看錯誤提示,在a.c中沒有發現f函數。我們很容易想到,這裡是不是不止從a.c中尋找f函數?或者這裡是不是可以不止從a.c中尋找?我們又聯想到TCC函數有同時編譯連接多個.c文件的選項。我們嘗試編寫兩個文件,並共同編譯:

clip_image010[4]

編譯連接過程:

clip_image011[4]

我們看到並沒有錯誤提示。並且在文件夾下生成了A.exe。我們運行查看:

clip_image012[4]

我們看到,將同一個程序寫在兩個文件中,程序也可以正常的編譯連接。

3.TLIB.exe

我們從書中看到,TC2.0給我們提供了一個工具tlib.exe,可以用tlib.exe將一個.obj文件中的代碼加到一個.lib文件中。

首先我們需要了解TLIB.exe的參數。我們仿照TCC的方法,在cmd中執行TLIB。其參數表如下:

clip_image013[4]

我們看到其參數,+是將一個文件添加進lib文件中。我們嘗試:

clip_image014[4]

clip_image015[4]

我們看其屬性,他確實被修改了。

clip_image016[4]

然後我們嘗試再次編譯a.c。發現沒有了錯誤提示:

clip_image017[4]

我們加載進debug,找到程序的main函數和f函數的代碼:

clip_image018[4]

我們看到main函數中只有一句調用的call指令,根據我們代碼的對比,我們知道這裡調用的就是f函數。我們查看f函數的代碼:

clip_image019[4]

我們運行:發現其實a.c調用的f()函數就是4_1.c中的f函數。

clip_image021[4]

回顧我們整個過程,我們可以得出這樣的結論,雖然我們沒有寫函數f,但是a.exe中函數f的代碼在連接的過程中從cs.lib中得到。

4.將下面的程序編譯為f.obj,將f.obj加入c:\c\cs.lib。

程序f.c如下:

clip_image022[4]

clip_image024[4]

下面的程序編譯連接為b.exe。

clip_image025[4]

我們編譯完成後進入debug查看。主函數中代碼如下:

clip_image026[4]

clip_image027[4]

看到,在函數調用的部分,都采用了call的方式,並且call的位置離主函數的比較遠。也就是說,call部分的函數沒有和main連續。我們轉跳到其調用的部分。查看其代碼。

clip_image028[4]

clip_image029[4]

我們對應f.c查看,我們可以看到,其實這三個子程序就是f1,f2,f3函數實現的語句。並且,雖然在b中沒有調用f3,f3的代碼也在b中。

很明顯,經過修改cs.lib,我們的程序可以調用f1,f2,這就說明了,b.exe中的代碼是在連接的時候從cs.lib中加入的。

那麼,是因為這三個函數在同一個文件中被加入cs.lib中,所以才出現這樣同時都被加載進入的結果麼?

我們把f3單獨拿出來,加入cs.lib(在此過程中,把cs.lib還原成tc2.0自帶的cs.lib)

clip_image030[4]clip_image031[4]

這時我們在編譯連接b.c,然後進入debug加載:

clip_image032[4]

clip_image033[4]

我們看到,這裡沒有了f3。那麼是不是被放在了其他地方呢?我們看看調用f3的時候它應該再什麼地方。

我們修改一下b.c,使他調用一下f3。

進入debug加載查看。

clip_image034[4]

clip_image035[4]

clip_image036[4]

我們看到,f3實現的子函數就在f1,f2的後面。也就是有如下事實:如果f3被調用,那麼他的地址就是在f2後面。如果f2後面沒有f3,也就是f3沒有被調用。這樣,就否定了f3在被放在了其他地方的推論。也進而說明了,分別編譯,分別加入cs.lib這個方案是可以實現用到哪個函數,裝入哪個函數的代碼的。

5.替換printf

用TLIB.EXE將cs.lib中的printf函數代碼變為下面程序的代碼:

clip_image037[4]

通過前面的幾個程序我們知道,cs.lib中也有printf函數對應的代碼。那麼我們就不能像前面的幾個程序那樣添加.obj進入cs.lib中了。而應該是替換。我們看TLIB.EXE的參數表,發現-+是替換的。我們嘗試:

clip_image038[4]

發現無錯誤提示。我們編寫一個程序如下,測試printf是否被替換成功:

clip_image039[4]

編譯連接後執行:

clip_image040[4]

這裡證實,printf確實被替換成了我們自己編寫的printf。

6.思考:

TCC這樣做有什麼好處呢?首先我們知道,在cs.lib中包含常用的一部分函數,可以使得TCC在編譯基本功能的程序時,不需要在包含頭文件。其次,我們知道,一般情況下,同一個文件中的函數之間一般是相互關聯的。有些是相互調用實現一個共同的功能,有些是實現不同的功能但是是對同一類數據操作的。這些函數寫在同一個文件中,包含的時候同時包含進去,這樣就減少了由於沒有包含而出現錯誤的情況。另外,可以自定義的替換其中的函數,保證了程序的多樣性和能夠方便的修改的特性。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved