預處理(Preprocessing)
- 任務:
處理源代碼中以#
開頭的預處理指令,包括:- 頭文件包含(#include):將頭文件(如 stdio.h)的內容直接插入到源文件中。
- 宏替換(#define):將代碼中的宏定義(如 #define PI 3.14)進行文本替換。
- 條件編譯(#ifdef #else #endif 等):根據條件決定代碼的保留或刪除(例如,區分調試和發布版本的代碼)。
- 輸出:生成一個經過預處理的中間文本文件(仍為可讀文本,但已展開所有預處理指令)。
編譯(Compilation)
- 任務:
將預處理后的代碼轉換為匯編語言代碼。編譯器會進行以下操作:- 詞法分析:將代碼分解成一個個單詞(Token),例如識別關鍵字、變量名、操作符等。
- 語法分析:檢查代碼是否符合 C/C++ 語法規則(如括號是否匹配、語句是否完整)。
- 語義分析:檢查代碼的語義正確性(如變量是否先定義后使用、類型是否匹配)。
- 中間代碼生成與優化:生成中間表示代碼,并進行優化(如刪除無用代碼、優化循環),最終轉換為匯編語言。
- 輸出:生成匯編代碼文件(如 Helloworld.s)。
匯編(Assembly)
- 任務:
匯編器(Assembler)將匯編語言代碼轉換為機器可識別的二進制目標文件(Object File,如 Helloworld.obj 或 Helloworld.o)。每個匯編指令會被映射為對應的機器碼。 - 輸出:生成二進制目標文件,此時文件中可能仍包含對其他函數(如標準庫函數 printf)的未解析引用。
鏈接(Linking)
- 任務:
鏈接器(Linker)將多個目標文件(包括自身代碼生成的 .obj 和依賴的庫文件)鏈接成一個可執行文件(如 Helloworld.exe)。分為兩種方式:- 靜態鏈接:將庫函數的代碼直接復制到可執行文件中,最終文件較大,但運行時無需依賴外部庫。
- 動態鏈接:僅記錄對庫函數的引用信息,運行時由操作系統加載對應的動態鏈接庫(如 .dll 在 Windows 或 .so 在 Linux)。
鏈接過程會解析目標文件中的外部符號引用(如解決 printf 的具體實現來自哪里)。
- 輸出:生成可直接運行的可執行文件。
運行(Execution)
- 任務:
操作系統加載可執行文件到內存中,創建進程,分配資源(如內存、文件句柄),然后執行程序的指令。程序從 main 函數開始執行,直到遇到 return 或 exit 等退出操作。