概述
1. C/C++源代碼從源文件到可執行文件需要經過預處理、編譯、匯編、鏈接等4個工作過程
預處理
1. 預處理主要是對偽指令和特殊符號進行處理,將.c文件轉為.i文件,具體處理如下:
(1)宏定義:如#define Name TockenString等,預編譯所要作的是將程序中的全部Name全部用TockenString替換
(2)處理所有的條件編譯指令,如#if、#endif、#ifdef等
(3)處理#include預編譯指令,將文件內容替換到它的位置,該過程是遞歸進行的
(4)刪除所有的注釋//和/**/
(5)保留所有的#pragma編譯器指令,編譯器需要使用它們
(6)添加行號和文件標識,便於編譯時編譯器產生調試用的行號信息,該行號也是編譯時產生編譯錯誤或警告能夠顯示行號
編譯
1. 編譯階段,主要是進行一些列詞法分析、語法分析、語義分析以及優化后,生成相應的匯編代碼.s文件
匯編
1. 匯編階段是將匯編代碼轉變為機器可執行的指令,匯編器的匯編過程,相對簡單,只是根據匯編指令和機器指令碼的對照表直接翻譯過程,會變完成后,可以將.s文件轉為.o文件
鏈接
1. 鏈接是將多個不同的源文件進行鏈接,從而形成一個可執行程序
2. 鏈接分為靜態鏈接和動態鏈接,靜態鏈接和動態鏈接的最大區別就是鏈接的時機不一樣,靜態鏈接是在形成可執行文件之前,動態鏈接是在程序執行時
(1) 一個源程序是由多個源文件組成的,多個源文件之間不是相關獨立的,而是存在多種依賴關系
(2)某個源文件會調用另一個源文件中的某個函數,但是每個源文件都是獨立編譯的,每個.c的源文件,會形成一個.o的目標文件
(3)為了滿足源文件之間的依賴關系,需要將這些源文件產生的目標文件進行鏈接,從而形成一個可執行文件
靜態鏈接
1. 源文件中的函數和數據預處理、編譯、匯編形成目標文件,而靜態鏈接庫就是多個目標文件的集合
2. 使用靜態鏈接庫時,鏈接器直接從庫中復制這些函數和數據,並將它們和應用程序的其他模塊組合起來,創建最終的可執行文件
3. 靜態鏈接是以目標文件為單位的,若多個函數都放在了一個目標文件中,可能很多沒有的函數也會被一起鏈接進入了輸出結果中
4. 缺點:
(1)每一個可執行文件中對所有需要的目標文件都需要一份副本,如果多個程序對同一個目標文件都有依賴,會出現同一個目標文件都在內存存在多個副本
(2)更新困難,每當庫函數的代碼發生改動,需要重新進行編譯、連接形成可執行程序
5. 優點:
(1)可執行程序中已經具備了所有執行程序所需要的任何東西,在執行的時候運行速度更快
動態鏈接
1. 動態鏈接的基本思想是把程序按照模塊拆分成各個相對獨立部分,在程序運行時才將它們鏈接在一起形成一個完整的程序,而不是像靜態鏈接那樣運行前就把所有程序模塊都鏈接成一個單獨的可執行文件
2. 動態鏈接的過程:
(1)假定程序p1.o和p2.o都依賴於庫lib.o,並且假定先運行p1.o,系統首先會加載p1.o,發現p1.o用到了lib.o然后將lib.o加載到內存
(2)當運行p2.o時,發現p2.o依賴於lib.o此時lib.o已經加載到內存中了,因此不需要重新加載,此時會將已經存在的lib.o映射到p2.o的虛擬地址空間中,從而進行鏈接,形成可執行文件
3. 優點:
(1)即使多個程序依賴於同一個庫,不會像靜態連接那樣在內存中存在多個副本,而是多個程序在執行時共享一份副本
(2)更新方便:更新時只需要替換原來的目標文件,而無需將所有程序都重新連接一遍,當程序下次運行時,新版本的目標文件會自動被加載到內存中並連接起來,完成了程序的更新
4. 缺點:
(1)由於連接過程從編譯階段,推遲到了程序運行時,所以運行速度相對於靜態鏈接更慢
4. 動態鏈接如何實現重定位的:
(1)在形成可執行文件時,發現引用了一個外部的函數,此時會檢查動態鏈接庫,發現函數名時一個動態鏈接符號,此時在可執行程序就不對這個符號進行重定位,就把這個過程留到裝載時在進行
參考文獻
1. 靜態鏈接和動態鏈接