
整個過程分為兩大階段:編譯(圖中大括號內)與 鏈接(其餘部分)。
處理以 # 開頭的預處理指令,生成 .i 文件(無宏、無條件編譯、無頭文件包含、無特殊符號)。
| 指令類型 | 代表指令 | 處理動作 |
|---|---|---|
| 宏定義 | #define, #undef | 宏展開/取消定義 |
| 條件編譯 | #ifdef, #ifndef, #else, #elif, #endif | 根據宏決定編碼保留/刪除 |
| 頭文件包含 | #include <>, #include "" | 將頭文件內容展開插入 |
| 特殊符號 | __LINE__, __FILE__, __FUNCTION__ | 替換為行號/文件名/函數名 |
關鍵點:<> 搜索系統目錄(/usr/include),"" 先搜當前目錄再搜系統目錄。
將匯編代碼(.s)翻譯為目標機器指令(.o 目標文件)。
目標文件結構:
三類目標文件(UNIX):可重定位文件、共享目標文件、可執行文件。
解決符號引用:將一個文件中對外部符號(變量/函數)的引用,與另一個文件中的定義關聯起來,形成統一可執行整體。
| 特性 | 靜態鏈接 | 動態鏈接 | ||
|---|---|---|---|---|
| 庫文件形式 | 靜態庫 .a(目標文件歸檔) | 動態庫 .so(共享對象) | ||
| 代碼拷貝 | 將函數代碼拷貝到可執行文件 | 僅記錄库名/符號信息 | ||
| 運行時行為 | 代碼隨進程加載 | 運行時映射到進程地址空間 | ||
| 優點 | 獨立性強、無依賴、移植性好 | 文件小、多進程共享內存、易升級 | ||
| 缺點 | 文件大、浪費內存、升級需重鏈接 | 有運行時開銷、依賴地獄、移植性弱 |
| 階段 | 輸入 | 輸出 | GCC 命令 | 底層工具 |
|---|---|---|---|---|
| 預處理 | .c | .i | gcc -E | cpp |
| 編譯 | .i | .s | gcc -S | cc1 |
| 匯編 | .s | .o | gcc -c | as |
| 鏈接 | .o | 可執行文件 | gcc | ld |
# 一步到位
gcc hello.c -o hello
# 分步驗證
gcc -E hello.c -o hello.i # 預處理
gcc -S hello.i -o hello.s # 編譯生成匯編
gcc -c hello.s -o hello.o # 匯編生成目標文件
gcc hello.o -o hello # 鏈接生成可執行文件
-I、-L、-l 作用機制-Wall -Wextra -Werror -pedantic本文整理自「成長之路」博客,原文地址:https://7905648.blog.51cto.com/7895648/1297255