目錄
前言
1.預處理:
宏替換:
頭檔案展開:
條件編譯:
2.編譯:
3.匯編:
4.鏈接:
前言
一個c/c++檔案想要變成可執行檔案要經過預處理生成預處理檔案(.i檔案),編譯階段對預處理檔案進行編譯生成匯編檔案(.s檔案),匯編階段對匯編檔案進行處理生成目標檔案(.o檔案),最后鏈接目標檔案生成可執行程式,下面我將介紹在各個階段對程式進行了哪些處理,
1.預處理:
c/c++源檔案中,以#開頭的命令被稱為預處理命令,如#include、#define、條件編譯命令#if、#ifdef等,所做的主要作業如下:
將所有的#define洗掉,并展開所有的宏定義
處理所有的條件預編譯指令,如:#if #ifdef #elif #else #endif
處理#include預編譯指令,將被包含的檔案插進到該指令的位置,這個程序是遞回的
洗掉所有的注釋//與/* */
添加行號與檔案名標識,以便產生除錯用的行號資訊以及編譯錯誤或警告時能夠顯示行號
保留所有的#pragma編譯器指令,因為編譯器需要使用它
宏替換:
#define可以定義宏也可以定義識別符號(重命名)

在預處理階段會把A替換成100,MAX(x,y)替換成(a)>(b)?(a):(b)要注意的是原封不動的替換,帶有引數時每個引數都要帶有括號,
需要注意的是宏引數和#define可以出現其他#define定義的變數,但是對于宏不能出現遞回,當前處理器 搜索#define定義的符號時,字串常量的內容并不被搜索,
頭檔案展開:
#include <> 是引系統提供的頭檔案,優先到庫里面去找, #include" "是引自己定義的頭檔案,優先到當前路徑去找,找到之后在#include<xx.h>的那一行,將xx.h這個頭檔案的內容原地展開替換這一行#include陳述句,
條件編譯:
就是選擇編譯,滿足條件就編譯不滿足條件就不編譯,

對于單分支因為1為真所以下面的printf會編譯,對于多分支就是考慮多種情況,當然A=100成立所以下一句會編譯A=200不成立所以不會編譯,#if defined(MAX)這是判斷MAX是否定義,定義了就編譯沒定義就不編譯,
2.編譯:
編譯階段做的事情就是對預處理檔案進行詞法分析(lex)、語法分析(yacc)、語意分析及優化(就是檢查語法)后生成匯編代碼生成匯編檔案(.s檔案),
3.匯編:
就是將編譯階段生成的匯編代碼轉換為計算機能識別的機器碼生成目標檔案(.o檔案),反匯編是指將機器代碼轉換為匯編代碼,這在除錯程式時常常用到,
通常一個目標檔案包含兩部分:
代碼段:該段中所包含的主要是程式的指令,該段一般是可讀和可執行的,但一般卻不可寫,
資料段:主要存放程式中要用到的各種全域變數或靜態的資料,一般資料段都是可讀,可寫,可執行的,
4.鏈接:
鏈接檔案主要是將有關的目標檔案彼此相連,就是在一個檔案中參考的符號和該符號在另一個檔案中的定義鏈接起來,使得這些目標檔案成為一個能被作業系統裝入執行的統一整體,
根據開發人員指定的同庫函式的鏈接方式的不同,鏈接處理可分為兩種,
(1)靜態鏈接
在這種鏈接方式下,函式的代碼將從其所在地靜態鏈接庫中被拷貝到最終的可執行程式中,這樣該程式在被執行時這些代碼將被裝入到該行程的虛擬地址空間中,靜態鏈接庫實際上是一個目標檔案的集合,其中的每個檔案含有庫中的一個或者一組相關函式的代碼,
(2) 動態鏈接
在此種方式下,函式的代碼被放到稱作是元件或共享物件的某個目標檔案中,鏈接程式此時所作的只是在最終的可執行程式中記錄下共享物件的名字以及其它少量的登記資訊,在此可執行檔案被執行時,元件的全部內容將被映射到運行時相應行程的虛地址空間,動態鏈接程式將根據可執行程式中記錄的資訊找到相應的函式代碼,
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/351030.html
標籤:其他
