生成乙個c++程式共有三個步驟:
①預處理:**在預處理器中執行,預處理器會識別**中的元資訊。
②編譯:**被編譯或轉換為計算機可以識別的目標檔案。
**的編譯過程鏈:
源**->預處理->編譯(翻譯過程)->彙編->目標檔案->鏈結->可執行程式
--《摘自c指標》,其中」翻譯過程「在原文中並沒有提到,是我加上去的
預處理
首先程式會被送交給預處理器。預處理器執行以#開頭的命令(指令)。
#include#include#include 「***.h」
#define max_cols 20
以上的**就稱為預處理指令,由預處理器解釋。
例如#include,#include指令告訴預處理器:提取標頭檔案中的所有內容並提供給當前檔案。
主要處理規則如下:(摘自程式設計師的自我修養)
①將所有的「#define」刪除,並且展開所有的巨集定義
②處理所有條件預編譯指令,比如「#if」,「#ifdef」,」#edlif」,「#else」,「endif」
③處理「#include」預編譯指令,將被包含的檔案插入到該預編譯指令的位置。注意,這個過程是遞迴進行的,也就是說被包含的檔案可能還包含其他檔案。
④刪除所有的注釋內容。
⑤新增行號和檔名標識,比如#2「hello.c」 2,以便於編譯時編譯器產生除錯用的行號資訊及用於編譯時產生編譯錯誤或警告時能夠顯示行號。
⑥保留所有的#pragma編譯器指令,因為編譯器須要使用它們。
翻譯過程(包含編譯和解釋)
把源**轉化成計算機能執行的形式(機器指令)。
翻譯器分為:直譯器和編譯器
直譯器
直譯器將源**轉化成一些動作(它可由多組機器指令組成)並立即執行這些動作。諸如python語言的直譯器,先把整個程式轉化成某種中間語言,然後由執行速度更快的直譯器來執行。
優點:
- 從寫**到執行**的轉換幾乎能立即完成。
- 源**一旦出現錯誤,直譯器能很容易地指出。
- 較好的互動性和適於快速程式開發
做大專案時有些侷限性:
- 直譯器必須駐留記憶體以執行程式。(執行會變慢)
- 大部分的直譯器要求一次輸入整個源**,造成記憶體空間的限制。
編譯器
修改後的程式現在可以進入編譯器了。編譯器會把程式翻譯成機器指令(即目標**)。編譯器直接把源**轉化成組合語言或機器指令,結果會是生成乙個或多個機器**的檔案。
優點:
編譯器生成的程式往往只需較少的執行空間,並且執行速度更快。
分段編譯
c語言可以分別編譯各段程式,然後使用聯結器把各段程式連線成乙個完成的可執行程式。
優點:
當建立和測試程式的一部分能夠正常執行後,就把它作為程式組塊儲存起來,並把它們一起收集加入庫中,供其他程式設計師使用,以此隱藏各段程式的複雜性。
直譯器和編譯器的關係
直譯器從寫**到執行**的能立即完成。例如程式除錯過程中,我們可以修改源**則立即看到程式被修改的效果。而編譯器是先直接把源**轉化成組合語言或機器指令,但這段過程還不能看到執行乙個程式的效果。使用編譯器時,從寫源**轉到執行**,是乙個較長的過程。
現代編譯器
為了提高編譯速度,一些編譯器採用了記憶體中編譯。大多數編譯器,編譯時每一步都要讀寫檔案。記憶體中編譯器幾乎能和直譯器一樣響應。
編譯一般分為兩遍進行:
①第一遍
首先對預處理過的**進行語法分析。編譯器把源**分解成小的單元並把它們按樹形結構組織起來。表示式」a+b」中的」a」,」+」和」b」就是語法分析樹的葉子節點。
②第一遍和第二遍之間(看具體情況而決定是否有這過程)
有時候會在編譯的第一遍和第二遍之間使用全域性優化器來生成更短,更快的**。
③第二遍
由**生成器遍歷語法分析樹,把樹的每個節點轉化成組合語言或機器**。如果**生成器生成的是組合語言,那麼還必須用彙編器對其彙編。不管**生成器生成的是組合語言,還是直接生成的是機器**,這兩種情況的最終結果都是生成目標模組。有時也會在第二遍中使用窺孔優化器從相鄰一段**中查詢冗餘彙編語句。
型別檢查
型別檢查是編譯器在第一遍中完成的。型別檢查是檢查函式引數是否正確使用,以防止許多程式設計錯誤。由於不是在程式執行階段進行的,所以稱為靜態型別檢查。c++預設不採用任何特殊的執行時支援來處理錯誤操作,但是我們可以通過編寫一些**以更換為動態型別檢查。
靜態型別檢查的優點:
靜態型別檢查在編譯時就告知程式設計師一些型別被誤用,從而加快了執行時的速度。
彙編
彙編器是彙編**轉變成機器可以執行的指令
目標檔案
鏈結
鏈結器把由編譯器產生的目標**和所需的其他附加**(包括庫函式)整合在一起,最終產生為完全可執行的程式。就是說鏈結器把一組目標模組連線成為乙個可執行程式,作業系統可以裝載和執行它。鏈結器能搜尋稱為「庫」的特殊檔案來處理它的所有引用。庫將一組目標模組包含在乙個檔案中。庫由乙個被稱為庫管理器的程式來建立和維護。
鏈結器如何查詢庫
①如果還未遇到過某個函式或變數的定義,聯結器會把它的識別符號加到「未解析的引用」列表中。
②如果聯結器遇到過函式或變數定義,那麼這就是已解決的引用。(例如引用不到動態鏈結庫,則就會報出「對xx未解析的引用」錯誤的資訊)
③如果聯結器在目標模組列表中不能找到函式或變數的定義,它將去查詢庫。
C C 生成可執行檔案過程
編譯的概念 編譯程式讀取源程式 字元流 對之進行詞法和語法的分析,將高階語言指令轉換為功能等效的彙編 再由匯程式設計序轉換為機器語言,並且按照作業系統對可執行檔案格式的要求鏈結生成可執行程式。編譯的完整過程 c源程式 預編譯處理 c 編譯 優化程式 asm s 匯程式設計序 obj o a 鏈結程式...
生成可執行檔案過程
c語言編譯全過程 編譯的概念 編譯程式讀取源程式 字元流 對之進行詞法和語法的分析,將高階語言指令轉換為功能等效的彙編 再由匯程式設計序轉換為機器語言,並且按照作業系統對可執行檔案格式的要求鏈結生成可執行程式。編譯的完整過程 c源程式 預編譯處理 c 編譯 優化程式 s asm 匯程式設計序 obj...
UNIX LINUX 平台可執行檔案載入過程
本文討論了 unix linux 平台下三種主要的可執行檔案格式 a.out assembler and link editor output 彙編器和鏈結編輯器的輸出 coff common object file format 通用物件檔案格式 elf executable and linkin...