標籤:
當我們編譯了一個c檔案,最終目的是讓它能夠成為可以執行的代碼,就是能夠受控或者控制硬體的東西。控制硬體的東西,一般都是二進位代碼。那麼,問題來了,從c到控制硬體的二進位代碼,中間經過了一個什麼流程呢?它的過程是這樣的:
一,編譯預先處理
讀取c源檔案,對其中的偽指令(以#開頭)和特殊符號進行處理;
偽指令包括:宏定義: 比如:#defile PI (3.1415)
條件編譯:#if (conditions) {do something} #else {do another thing} #endif
或#ifdef #ifndef #elif 等等。
標頭檔:#include <filename>, #include "filename" 標頭檔中的#ifndef __XXX_H__ #def __XXX_H__是為了防止避免標頭檔重複包含而導致程式出錯。
特殊符號:主要有__func__、__LINE__、__FILE__等
預先處理的工作其實就是將上面的偽指令和特殊符號展開,替換掉原來的c檔案,這裡不做文法的檢查,僅僅是替換。
二,編譯階段
預先處理後,進行的文法和詞法的分析,確認指令都符合文法規則後,將其翻譯成等價的中間代碼或彙編代碼。
三,最佳化階段
中間代碼的最佳化,主要的工作是刪除公用運算式、迴圈最佳化(代碼外提、強度削弱、變換迴圈控制條件、已知量的合并等)、複寫傳播,以及無用賦值的刪除,等等。
偏向硬體執行的最佳化,考慮是如何充分利用機器的各個硬體寄存器存放的有關變數的值,以減少對於記憶體的訪問次數。另外,如何根據機器硬體執行指令的特點(如流水線、RISC、CISC、VLIW等)而對指令進行一些調整使目標代碼比較短,執行的效率比較高。
四,彙編過程
將組合語言代碼翻譯成目標機器指令的過程。對於被翻譯系統處理的每一個C語言來源程式,都將最終經過這一處理而得到相應的目標檔案。目標檔案中所存放的也就是與來源程式等效的目標的機器語言代碼。OK,這裡的意思就是彙編是將最佳化後的彙編代碼,翻譯成一個目標檔案。但是這個這個目標檔案能執行嗎?不能!!!因為在這個目標檔案中,可能需要到其他庫或者其他檔案的一些函數,所以還要有一個連結的過程。這裡先說說目標檔案:
目標檔案由段組成。通常一個目標檔案中至少有兩個段:
程式碼片段 該段中所包含的主要是程式的指令。該段一般是可讀和可執行檔,但一般卻不可寫。
資料區段 主要存放程式中要用到的各種全域變數或靜態資料。一般資料區段都是可讀,可寫,可執行檔。 五,連結程式 就是剛才說的彙編後產生的目標檔案需要連結到一些庫或者其他檔案以擷取自己源碼內引用的函數,符號等。連結程式的主要工作就是將有關的目標檔案彼此相串連,也即將在一個檔案中引用的符號同該符號在另外一個檔案中的定義串連起來,使得所有的這些目標檔案成為一個能夠被作業系統裝入執行的統一整體。 連結分為靜態和動態。靜態就是涉及到的函數和符號,直接從源檔案中copy過來,形成最終的可執行檔。動態只是記錄這些函數和符號的一些資訊,在執行的時候才從記憶體中尋找,並映射到可執行檔的進程虛擬空間中。 兩種方式對比:靜態安全,但是可執行檔佔用記憶體空間較大。動態靈活,佔用記憶體小,但是效能上可能會受到一些損害。 經過這5步,一個c檔案就可以被編譯成可執行檔檔案,預設為a.out. 參考:http://lavasoft.blog.51cto.com/62575/187229/ 關於最佳化選項的一些介紹: 經常能看到gcc後有-O、-O1、-O2、-O3,這些代表什麼意思呢?這些屬於最佳化的選項,包括簡化目標代碼的長度,最佳化執行時間等。具體的參看下面的連結: 中文的一些簡介:http://blog.chinaunix.net/uid-23916171-id-2653114.html 最佳化項的解釋:http://gcc.gnu.org/onlinedocs/gcc-4.8.1/gcc/Optimize-Options.html#Optimize-Options
C程式編譯過程及最佳化選項介紹