要更深入了解c++, 必須要知道乙個程式從開始到結束都幹了些什麼, 怎麼幹的。 所以我從c++編譯到執行過程,解析下程式是怎麼跑的。
首先,初略的說一下之前c++的編譯過程,c++編譯過程包括預編譯-》彙編-》編譯-》鏈結。稱為乙個可執行檔案。(windows平台下為.exe檔案)。
預編譯主要展開包含的標頭檔案,巨集定義等操作。例如乙個簡單的main程式,編譯預編譯後,的檔案對比。
彙編過程,就是把已經預編譯的檔案編譯成彙編**的過程,整個過程會包含語法,詞法的分析,和一些優化操作。
編譯過程其實是跟彙編可以合成乙個階段,變成目標**。也就是二進位制檔案。
鏈結過程是將單個編譯後的檔案鏈結成乙個可執行程式。前面的預編譯、彙編、編譯都是正對單個檔案,以乙個檔案為乙個編譯單元,而鏈結則是將所有關聯到的編譯後單元檔案和應用的到庫檔案,進行一次鏈結處理,之前編譯過的檔案 如果有用到其他檔案裡面定義到的函式,全域性變數,在這個過程中都會進行解析。
首先看看編譯後的檔案樣子(已vs2012編譯後的obj檔案為例子,不同編譯器 樣式可能會不同。)
編譯前的檔案
#include "car.h"
int main(int argc, char* argv)
編譯後的樣子(由於編譯後的檔案 資訊太多 只貼出裡面未解析符號部分。)
undef:00002dc4 ; int __thiscall car::car(car *__hidden this)
undef:00002dc4 extrn ??0car@@qae@xz:near ; code xref: _main+63p
undef:00002dc8 ; int __thiscall car::~car(car *__hidden this)
undef:00002dc8 extrn ??1car@@qae@xz:near
undef:00002dc8 ; code xref: car::`scalar deleting destructor'(uint)+26p
undef:00002dcc ; __fastcall _rtc_checkstackvars(x, x)
undef:00002dcc extrn @_rtc_checkstackvars@8:near
undef:00002dcc ; code xref: std::_string_alloc<0,std::_string_base_types>>::_alloc_proxy(void)+68p
undef:00002dcc ; $ln19+72p ...
undef:00002dd0 ; __fastcall __security_check_cookie(x)
undef:00002dd0 extrn @__security_check_cookie@4:near
undef:00002dd0 ; code xref: __ehhandler$??$construct@padaapad@?$allocator@d@std@@qaexpapadaapad@z+fp
undef:00002dd0 ; __ehhandler$??$construct@u_container_proxy@std@@u12@@?$allocator@u_container_proxy@std@@@std@@qaexpau_container_proxy@1@$$qau21@@z+fp ...
undef:00002dd4 ; __stdcall _cxxthrowexception(x, x)
編譯後的檔案用(用反彙編成彙編**檢視) 其中實現函式會變成一堆彙編指令。而那些引用到的在其他檔案裡面實現的函式將會變成乙個特點的符號(如上面中的呼叫car類的建構函式 extrn??0car@@qae@xz:near)這些符號稱做為解析的符號,表示在鏈結的時候需要被解析。符號的生成名稱具體跟編譯器有關,但是會保證乙個類的某個函式名稱在同乙個編譯裡面必須是唯一的,因為我們在預編譯階段已經把car.h包含進來所以編譯器能正確生成這個函式的名字,然後在鏈結的時候 會找到改名字的函式,把此標識名字替換為函式的位址。這樣就實現的鏈結。
在符號解析(symbol resolution)階段,鏈結器按照所有目標檔案和庫檔案出現在命令列中的順序從左至右依次掃瞄它們,在此期間它要維護若干個集合:(1)集合e是將被合併到一起組成可執行檔案的所有目標檔案集合;(2)集合u是未解析符號(unresolved symbols,比如已經被引用但是還未被定義的符號)的集合;(3)集合d是所有之前已被加入到e的目標檔案定義的符號集合。一開始,e、u、d都是空的。
(1): 對命令列中的每乙個輸入檔案f,鏈結器確定它是目標檔案還是庫檔案,如果它是目標檔案,就把f加入到e,並把f中未解析的符號和已定義的符號分別加入到u、d集合中,然後處理下乙個輸入檔案。
(2): 如果f是乙個庫檔案,鏈結器會嘗試把u中的所有未解析符號與f中各目標模組定義的符號進行匹配。如果某個目標模組m定義了乙個u中的未解析符號,那麼就把 m加入到e中,並把m中未解析的符號和已定義的符號分別加入到u、d集合中。不斷地對f中的所有目標模組重複這個過程直至到達乙個不動點(fixed point),此時u和d不再變化。而那些未加入到e中的f裡的目標模組就被簡單地丟棄,鏈結器繼續處理下一輸入檔案。
(3): 如果處理過程中往d加入乙個已存在的符號,或者當掃瞄完所有輸入檔案時u非空,鏈結器報錯並停止動作。否則,它把e中的所有目標檔案合併在一起生成可執行檔案。
C語言從編譯到執行過程詳解
目錄 最近在看csapp 深入理解計算機系統 然後以前也學過c語言,但是從來沒有深究寫好的c 是怎麼編譯再到執行的。所以現在自己學習,然後記錄下來。以最常用的hello world!程式為例 程式名 main.c include int main hel程式設計客棧lo程式的生命週期是從乙個高階c語...
C編譯執行的過程
c編譯執行是c語言必學的的。從巨集觀上來說主要分成了 c源 編譯 鏈結 執行 從微觀上來說 c源程式標頭檔案 預編譯處理 cpp 編譯程式本身 優化程式 匯程式設計序 鏈結程式 可執行檔案 a 預編譯處理 將偽指令和特殊的符號進行處理。預處理就是將原始檔的包含標頭檔案,巨集定義,條件編譯等進行簡單的...
C程式編譯執行過程
c語言從源 到可執行檔案的過程 1 編譯預處理 讀取c源 對其中的偽指令 以 開頭的指令 和特殊符號進行處理 偽指令主要包括以下四個方面 1.1 巨集定義指令 define 定義巨集 undef 取消巨集的定義 預定義巨集 標準c中定義了一些物件巨集,這些巨集的名稱以 兩個下劃線 開頭和結尾,並且都...