編譯流程分為四個階段:預處理、編譯、匯編、鏈接
以Linux系統下g++編譯為例:
通過g++的選項可以查看過程中的每一步
預處理:處理一些#號定義的命令或語句(如#define、#include、#ifdef等),生成.i文件
編譯:進行詞法分析、語法分析和語義分析等,生成.s的匯編文件
匯編:將對應的匯編指令翻譯成機器指令,生成二進制.o目標文件
鏈接:鏈接分為兩種
靜態鏈接
在鏈接期,將靜態鏈接庫中的內容直接裝填到可執行程序中。
在程序執行時,這些代碼都會被裝入該進程的虛擬地址空間中。
動態鏈接
在鏈接期,只在可執行程序中記錄與動態鏈接庫中共享對象的映射信息。
在程序執行時,動態鏈接庫的全部內容被映射到該進程的虛擬地址空間。其本質就是將鏈接的過程推遲到運行時處理
擴展:
01 為什么要有靜態鏈接?
在我們的實際開發中,不可能將所有代碼放在一個源文件中,所以會出現多個源文件,而且多個源文件之間不是獨立的,而會存在多種依賴關系,如一個源文件可能要調用另一個源文件中定義的函數,但是每個源文件都是獨立編譯的,即每個.c文件會形成一個.o文件,為了滿足前面說的依賴關系,則需要將這些源文件產生的目標文件進行鏈接,從而形成一個可以執行的程序。這個鏈接的過程就是靜態鏈接
由很多目標文件進行鏈接形成的是靜態庫,反之靜態庫也可以簡單地看成是一組目標文件的集合,即很多目標文件經過壓縮打包后形成的一個文件
02 靜態鏈接的優缺點缺點:
浪費空間,因為每個可執行程序中對所有需要的目標文件都要有一份副本,如果運行多個程序并且這些程序都對同一個目標文件有依賴,那么目標文件在內存中就會存在多個副本;
更新困難,因為每當一個依賴文件的代碼修改了,這個時候就需要全部重新編譯鏈接形成新的可執行程序。
優點:
運行速度快并且不依賴外部環境,因為在可執行程序中已經具備了所有執行程序所需要的任何東西,在執行的時候運行速度快。
注意:我們知道,鏈接器在鏈接靜態鏈接庫的時候是以目標文件為單位的。比如我們引用了靜態庫中的printf()函數,那么鏈接器就會把庫中包含printf()函數的那個目標文件鏈接進來,如果很多函數都放在一個目標文件中,很可能很多沒用的函數都被一起鏈接進了輸出結果中。由于運行庫有成百上千個函數,數量非常龐大,每個函數獨立地放在一個目標文件中可以盡量減少空間的浪費,那些沒有被用到的目標文件就不要鏈接到最終的輸出文件中。
03 為什么要有動態鏈接?
為了解決靜態鏈接中提到的兩個問題,一方面是空間浪費,另外一方面是更新困難。
流程簡介:
假設現在有兩個程序program1.o和program2.o,這兩者共用同一個庫lib.o,假設首先運行程序program1,系統首先加載program1.o,當系統發現program1.o中用到了lib.o,即program1.o依賴于lib.o,那么系統接著加載lib.o,如果program1.o和lib.o還依賴于其他目標文件,則依次全部加載到內存中。當program2運行時,同樣的加載program2.o,然后發現program2.o依賴于lib.o,但是此時lib.o已經存在于內存中,這個時候就不再進行重新加載,而是將內存中已經存在的lib.o映射到program2的虛擬地址空間中,從而進行鏈接.
04 動態鏈接的優缺點優點:
節約內存:即使需要每個程序都依賴同一個庫,但是該庫不會像靜態鏈接那樣在內存中存在多分,副本,而是這多個程序在執行時共享同一份副本;
更新方便:更新時只需要替換原來的目標文件,而無需將所有的程序再重新鏈接一遍。當程序下一次運行時,新版本的目標文件會被自動加載到內存并且鏈接起來,程序就完成了升級的目標。
缺點:
性能略差:因為把鏈接推遲到了程序運行時,所以每次執行程序都需要進行鏈接,所以性能會有一定損失。
依賴外部環境:因為把鏈接推遲到了程序運行時,所以要保證程序運行時外部的庫存在且內容正確無誤。
審核編輯:郭婷
-
Linux
+關注
關注
87文章
11322瀏覽量
209860 -
C++
+關注
關注
22文章
2112瀏覽量
73716
原文標題:C/C++的編譯流程?
文章出處:【微信號:嵌入式學習站,微信公眾號:嵌入式學習站】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論