是的,**C 語言寫出的代碼全都是「源程序」**。除非你直接輸入機器碼(二進制指令),否則任何高級語言(C、C++、Java、Python…)編寫的文本文件,都需要經過 編譯/解釋 才能成為 CPU 可執行的機器碼。
hello.c (源程序,文本)
│
▼ 預處理 (cpp) - 展開宏、包含頭文件、刪除註釋
hello.i (預處理後源碼)
│
▼ 編譯 (cc1) - 詞法/語法分析、優化、生成汇編
hello.s (汇編代碼,文本)
│
▼ 汇編 (as) - 汇編指令 → 機器指令
hello.o (目標文件,二進制,含符號表、重定位表)
│
▼ 鏈接 (ld) - 合併多目標文件、解析符號、鏈接庫
a.out / hello.exe (可執行文件,二進制,含加載信息)
│
▼ 加載器 (OS) - 映射到內存、動態鏈接共享庫
進程映像 (內存中,CPU 直接取指執行)
| 術語 | 本質 | 可讀性 | 可移植性 |
|---|---|---|---|
| 源程序 | 高級語言文本 | 人類可讀 | 跨平台(同源碼可編譯到不同架構) |
| 汇編代碼 | 助記符文本 | 專業人員可讀 | 特定指令集(x86/ARM/RISC-V) |
| 目標文件 | 二進制機器碼 + 元數據 | 不可直接讀 | 特定架構 + ABI |
| 可執行文件 | 完整加載映像 | 不可直接讀 | 特定 OS + 架構 (ELF/PE/Mach-O) |
| 機器碼 | 純二進制指令流 | 極難讀 | 極強綁定 CPU 型號 |
-g 將源碼行號嵌入目標/可執行文件,GDB 才能定位到 hello.c:10。.c 只需重新編譯該文件到 .o,再鏈接,大幅縮短構建時間。.o 到 .exe 過程,才能搞懂 undefined reference、LD_LIBRARY_PATH、符號衝突。.c 源程序,換交叉編譯器即可產出 ARM、RISC-V、WASM 目標文件。極少數場景(Bootloader、OS 內核入口、JIT 編譯器)會手寫十六進制機器碼:
// x86-64 機器碼:mov eax, 1; ret (sys_exit)
unsigned char code[] = {0xB8, 0x01, 0x00, 0x00, 0x00, 0xC3};
((void(*)())code)(); // 強制執行(需內存可執行權限 mprotect)
這才是真正「非源程序」的編程,但屬於系統級黑魔法,日常開發完全不涉及。
源程序 = 給人看的邏輯描述,可執行文件 = 給 CPU 看的指令流。C 語言編程的本質就是編寫源程序,借助工具鏈將其轉化為目標平台的可執行文件。理解這一鏈路,是從「寫代碼」進化為「工程師」的分水嶺。