1、編譯預先處理:
編譯器讀取C來源程式,對其中的預先處理命令(以#開頭)和特殊符號進行處理。預先處理命令包括主要包括三種,一是宏定義命令,二是條件編譯指令,三是標頭檔包含指令。採用標頭檔的目的是使某些定義可以供多個不同的C來源程式使用。在需要用到這些定義的C來源程式中,只需加上#include語句即可,而不必重新定義一遍。先行編譯程式將標頭檔中的代碼統統加入到源檔案,進而產生輸出檔案。
除了以上三種預先處理命令,還有特殊符號。先行編譯程式可以識別一些特殊符號。例如在來源程式中出現的LINE表示將被解釋為十進位表示的當前行號。FILE則被解釋為當前編譯的來源程式的檔案名稱。
先行編譯程式完成的工作,可以說成是對來源程式的“替換”工作。經過這個過程,產生一個沒有宏定義、沒有條件編譯指令、沒有特殊符號的輸出檔案。
2、編譯、最佳化:
編譯器的工作是,通過詞法分析、文法分析,在確認所有的指令都符合文法規則之後,將其翻譯成等價的中間代碼或彙編代碼。
在產生中間代碼或彙編代碼過程中,可能涉及到最佳化處理。最佳化有兩種:一種最佳化僅涉及代碼本身,主要是刪除公用運算式、迴圈最佳化、代碼外提、無用代碼賦值的刪除等。另一種最佳化設計具體的電腦硬體,比如,如何根據機器硬體執行指令的特點對指令進行調整最佳化,減少目標代碼長度,提高執行效率。
中間代碼或者彙編代碼產生以後,編譯器將中間代碼轉換為目標機器指令的序列,得到對應於來源程式的目標檔案。目標檔案中存放的也就是與來源程式等效的目標機器的機器語言代碼。目標檔案一般至少包含2個段:程式碼片段和資料區段。
3、連結:
由第二階段產生的若干對應於多個來源程式的目標檔案,並不能立即就被執行。其中存在一些問題,比如,某個源檔案中的函數可能引用了另一個源檔案中的某個符號(如變數或者函數等);在一個源檔案中可能調用了某個庫檔案中的函數,等等。這些問題,需要串連程式來解決。
串連程式的主要工作就是將有關的目標檔案彼此串連。也就是將在一個檔案中引用的符號同該符號在另一個檔案中的定義串連起來。使得所有這些目標檔案成為一個能夠被作業系統執行的一個整體。
補充:連結庫分為2種
靜態連結
在這種串連方式下,函數的代碼將直接拷貝到最終的可執行檔中。該程式被執行時候,會被裝入該進程的虛擬位址空間中。靜態連結庫實際上是一個或若干目標檔案。
動態連結
這種方式下,函數的代碼被放到稱作動態串連庫或共用對象的某個目標檔案中。連結程式此時的工作只是在產生的可執行檔中,記錄下共用對象的名字以及少量關鍵資訊。動態串連庫可以被多個進程共用,在運行時候記憶體中只有一個執行個體。
二者比較
使用動態連結能夠使可執行檔較小,並且當共用對象被多個進程使用時節省記憶體。但有時候系統運行改變或省級,不能保證動態串連庫一定可用、有效。