天天看點

C++從源檔案到可執行檔案 & 目标檔案 & 連結

C++從源檔案到可執行檔案的過程、

源代碼–>編譯預處理–>編譯–>優化–>彙編–>連結–>可執行檔案

具體如下:

編譯預處理-宏、條件編譯指令-頭檔案指令

讀取源程式,對其中的僞指令(以#開頭的指令)和特殊符号進行預處理。

宏定義指令:如#define Name TokenString #undef等。對于#define,預編譯所做的就是将程式中的Name全部替換成TokenString。對于後一個,則取消宏定義,使得字元串Name不被替換。

條件編譯指令:#ifdef #ifndef #else #elif #endif等。這些僞指令的引入使得程式員來區差別定義不同的宏來決定編譯對哪些代碼進行處理。預編譯程式根據有關的檔案,将哪些不必要編譯的代碼過濾掉。

頭檔案包含指令:#include 。預編譯程式将頭檔案的定義統統加入到它所長生的輸出檔案中,以供編譯檔案使用。

特殊符号:預編譯可以識别一些預編譯符号。

編譯階段-主要是文法處理

經過預編譯處理的輸出檔案中,将隻有常量。如數字、字元串、變量的定義,以及語言的關鍵字,如main、if、while等。預編譯工作是通過詞法分析和文法分析,在确認所有的指令都符合文法規則後,将其翻譯成等價的中間代碼表示或者彙編代碼。

優化階段

優化處理是編譯系統中一項比較艱深的技術。它涉及到的問題不僅同編譯技術本身有關,而且同機器的硬體環境也有關系。優化一部分是對中間代碼的優化。這種優化不依賴于計算機。另一種優化則是針對目标代碼的生成進行。

對中間代碼的優化:删除公共表達式、循環優化(強度削弱、代碼外提、已知代變量合并等)、無用指派等。

對目标代碼的優化:同機器的硬體結構緊密相關,最主要考慮是如何充分利用機器的各個硬體寄存器存放的有關變量的值,以減少對于記憶體的通路次數。另外,根據機器硬體執行指令的特點而對指令進行一些調整使目标代碼比較簡短,執行效率高。

彙編階段

彙編過程實際上是指吧彙編語言翻譯成目标機器指令的過程。

連結程式

由彙程式設計式生成的目标檔案并不能立即被執行。

連結程式是将有關的目标檔案批次連結,也即将一個檔案中引用的符号同該符号所在的另外一個檔案中的定義連結起來,使得所有的這些目标檔案成為一個能夠作業系統裝入執行的統一整體。

靜态連結:函數的代碼将從其他靜态連結庫中拷貝在最終的可執行檔案。

動态連結:函數的代碼被放到成為動态連結庫或共享對象的某個目标檔案中。連結程式隻是在最終可執行程式中記錄下共享對象的名字以及其他少量登記資訊。

目标檔案裡面是什麼?什麼結構?

編譯器編譯源代碼後生成的檔案叫做目标檔案。從檔案結構上來講,目标檔案已經是二進制檔案。編譯是針對單個源檔案的,有幾個源檔案就會生成幾個目标檔案,并且在生成過程中不受其他源檔案的影響。也就是說,不管目前工程中有多少個源檔案,編譯器每次隻編譯一個源檔案、生成一個目标檔案。

連結是什麼?靜态連結、動态連結是什麼,它們具體做了什麼?

由彙程式設計式生成的目标檔案并不能立即被執行。

連結程式是将有關的目标檔案批次連結,也即将一個檔案中引用的符号同該符号所在的另外一個檔案中的定義連結起來,使得所有的這些目标檔案成為一個能夠作業系統裝入執行的統一整體。

靜态連結 在這種連結方式下,函數的代碼将從其所在地靜态連結庫中被拷貝到最終的可執行程式中。這樣該程式在被執行時這些代碼将被裝入到該程序的虛拟位址空間中。靜态連結庫實際上是一個目标檔案的集合,其中的每個檔案含有庫中的一個或者一組相關函數的代碼。(個人備注:靜态連結将連結庫的代碼複制到可執行程式中,使得可執行程式體積變大)

動态連結  在此種方式下,函數的代碼被放到稱作是動态連結庫或共享對象的某個目标檔案中。鍊指連結階段僅僅隻加入一些描述資訊,而程式執行時再從系統中把相應動态庫加載到記憶體中去。連結程式此時所作的隻是在最終的可執行程式中記錄下共享對象的名字以及其它少量的登記資訊。在此可執行檔案被執行時,動态連結庫的全部内容将被映射到運作時相應程序的虛位址空間。動态連結程式将根據可執行程式中記錄的資訊找到相應的函數代碼。(個人備注:動态連結指的是需要連結的代碼放到一個共享對象中,共享對象映射到程序虛位址空間,連結程式記錄可執行程式将來需要用的代碼資訊,根據這些資訊迅速定位相應的代碼片段。)

繼續閱讀