C 語言程式從文本源碼到可執行檔案,經歷**預處理、編譯、匯編、鏈接**四大階段。理解這一流程,是排查編譯錯誤、優化建置速度、實現跨平台建置的基石。
| 環境 | 名稱 | 功能 | 關鍵點 |
|---|---|---|---|
| 翻譯環境 | Translation Environment | 源程式 → 機器指令 | 包含預處理器、編譯器、匯編器、鏈接器 |
| 執行環境 | Execution Environment | 執行機器指令 | 載入器、執行時庫、作業系統核心 |
**關鍵認知**:翻譯環境與執行環境**不必在同一台機器**(交叉編譯即是如此)。
// 輸入:hello.c → 輸出:hello.i (展開後的純 C 碼) gcc -E hello.c -o hello.i
#define PI 3.14 → 文本替換#ifdef DEBUG ... #endif → 選擇性保留碼#include <stdio.h> → 將標頭檔內容原位展開__LINE__、__FILE__、__DATE__、__TIME__、__func__ → 替換為當前行號、檔案名、編譯日期/時間、函數名// 輸入:hello.i → 輸出:hello.s (匯編語言) gcc -S hello.i -o hello.s
// 輸入:hello.s → 輸出:hello.o (ELF/COFF/Mach-O 目標檔) gcc -c hello.s -o hello.o // 或直接:gcc -c hello.c -o hello.o
// 輸入:main.o, utils.o, libm.a ... → 輸出:hello (可執行檔) gcc main.o utils.o -o hello -lm
| 指令 | 作用 | 輸出 |
|---|---|---|
gcc prog.c | 完整流程生成可執行檔 | a.out (或 a.exe) |
gcc prog.c -o prog | 指定輸出檔名 | prog |
gcc -c prog.c | 僅編譯到目標檔 | prog.o |
gcc -E prog.c | 僅預處理 | 標準輸出 (.i) |
gcc -S prog.c | 僅編譯到匯編 | prog.s |
gcc main.c utils.c | 多檔一次編譯鏈接 | a.out (保留 .o) |
gcc -Wall -Wextra -O2 | 開啟警告與優化 | 高品質建置 |
ELF Header Program Header Table (段資訊,載入器使用) +------------------+ | .text (程式碼) | ← RX | .rodata (常量) | ← R | .data (已初始化全域/靜態) | ← RW | .bss (未初始化全域/靜態) | ← RW (檔案中不佔空間) | .symtab (符號表) | | .strtab (字串表) | | .rel.* (重定位表)| +------------------+ Section Header Table (鏈接器/除錯器使用)
gcc -E hello.c | grep -A5 -B5 "printf" 確認宏展開、標頭檔包含是否正確。gcc -S -O2 hello.c -o - | less 分析編譯器優化效果。nm hello.o、objdump -t hello.o 確認函數/變數可見性。ldd hello (Linux)、otool -L hello (macOS)。掌握「預處理→編譯→匯編→鏈接」四階段輸入輸出、中間產物格式、工具鏈指令,能讓你從「會寫代碼」進化為「懂建置系統」,精準定位「未定義引用」「多重定義」「標頭檔重複包含」「ABI 不兼容」等疑難雜症。