程式的預編譯,編譯,彙編,鏈結過程

2021-07-30 23:12:41 字數 2026 閱讀 9808

預編譯過程主要處理那些源**檔案中的以」#」開始的預編譯指令。比如:」#include」,」#define」等,主要處理規則如下:

(1)將所有的」#define」刪除,並且展開所有的巨集定義。

(2)處理所有條件預編譯指令,

比如」#if」,」#ifdef」,」#elif」,」#else」,」#endif」.

(3)處理」#include」預編譯指令,將被包含的檔案插入到該預編譯指令的位置。注意:這個過程是遞迴進行的,也就是說被包含的檔案可能還包含其他檔案。

(4)刪除所有注釋」//」和」/**/.

(5)新增行號和檔名標識,比如#2 」hello.c」 2,以便與變異是編譯器產生條使用的行號資訊以及用於編譯時產生編譯錯誤或警告時能夠顯示行號。

(6)保留所有的」#pragma」編譯器指令,因為編譯器需要使用它們。

經過編譯後的.i檔案不包含任何巨集定義,因為所有的巨集定義都已經展開,並且包含的檔案也已經被插入到.i檔案中。

編譯過程就是把預處理完的檔案進行一系列詞法分析,語法分析,語義分析,優化後生成相應的彙編**檔案。

(1)詞法分析:

詞法分析產生的記號一般可分為以下幾類:關鍵字,識別符號,字面量(包含數字,字串等)和特殊符號(如加號,等號等)。

實現詞法掃瞄的工具是lex,他會按照使用者之前描述好的詞法規則將輸入號的字串分割成乙個個記號。

(2)語法分析:

語法分析器將對由掃瞄器產生的記號進行語法分析,從而產生語法樹(以表示式為節點的樹)。

實現語法分析的工具是yacc,可以根據使用者給定的語法規則對輸入的記號序列進行解析,從而構建出一顆語法樹。

(3)語義分析:

編譯器能進行的語義分析是靜態語義分析(指在編譯器期間可以確定的語義),靜態語義經常包括宣告和型別的匹配,型別的轉換。

(4)中間語言生成:

原始碼級優化器在不同編譯器中可能有不同的定義或有一些差異,源**級優化器會在源**級別進行優化,源**級優化器往往將整個語法書轉換成中間**,它是語法樹的順序表示。

中間**有多種型別,在不同的編譯器中有不同的形式,常見的有:三位址碼和p-**。

中間**將編譯器分為前端和後端,編譯器前端負責產生機器無關的中間**,編譯器後端將中間**轉換成目標機器**。

(5)目標**生成與優化:

編譯器後端主要包括**生成器和目標**優化器,**生成器將中間**轉換成目標**,目標**優化器將對上述的目標**進行優化,比如選擇合適的定址方式,使用位移來代替乘法運算,刪除多餘的指令等等。

彙編器是將彙編**轉變為機器可執行指令,每一彙編語句幾乎對應一條機器指令。

兩種方法都可使用生成機器指令:

as指令和gcc -c 指令:

靜態語言的c/c++模組之間通訊之間有兩種方式:一種是模組間的變數訪問,一種是模組間的函式呼叫,函式訪問需要知道目標函式的位址,變數訪問也需要知道目標變數的位址,因此可以將兩種方式歸結為一種方式,即就是模組間符號的引用

鏈結的主要內容就是把各個模組之間相互引用的部分都處理好,使得各個模組之間能夠正確的鏈結。

使用鏈結器可以直接引用其他模組的函式和全域性變數而無需知道他們的位址,因為鏈結器在連線的時候,會根據所引用的符號foo,自動去相應的func.c模組去查詢符號foo的位址,然後將main.c模組中所有引用到foo的指令重新修正,讓他們的目標位址為真正的foo函式的位址。

預編譯 編譯 彙編 鏈結過程

將源 或者標頭檔案經過預編譯成乙個.i檔案。例如c 副檔名是.cpp,標頭檔案的副檔名可能是.hpp,預編譯後的副檔名是.i 預編譯的過程相當於下面的命令 對c語言檔案的處理 gcc e 原始檔 o目標檔案 對c 語言的檔案的處理 g gcc e 原始檔 o目標檔案 例如 gcc e hello.c...

Linux 預編譯 編譯 彙編 鏈結過程

當我們拿到乙個.cpp的檔案,我們看到它的 但我們又是知道它是怎樣執行的?我們都知道我們所看到的 都是高階語言。但計算機底層只能識別像0,1這樣的低階語言,所以這也是乙個將c c 轉成組合語言然後再變成機器語言的過程。具體可分為預編譯 編譯 彙編 鏈結四個過程。一 在liunx中這四個階段的具體命令...

編譯的整個過程 預編譯 編譯 彙編 鏈結

編譯分為四個步驟 每個步驟將檔案編譯成別的格式,如下 步驟未編譯 預編譯編譯 彙編鏈結 檔案fun.h fun.cpp test.cpp fun.i test.i fun.s test.s fun.o test.o projectname.exe 詳解 1.預編譯 預編譯過程主要做4件事 展開標頭檔...