| 層級 | 標誌性能力 | 典型問題 | 突破鑰匙 |
|---|---|---|---|
| L1 语法熟练 | 能寫出編譯通過、跑出正確結果的代碼 | 「為什麼這裡要加 &?」 | 大量編碼、背誦語法規則 |
| L2 內存模型 | 理解棧/堆/數據段、指針算術、數組退化、結構體對齊 | 「為什麼這裡 Segfault?」 | 畫內存圖、用 GDB 觀察地址、Valgrind/ASan |
| L3 未定義行為 | 能識別並規避 UB(有符號溢出、空指針解引用、序列點、嚴格別名) | 「為什麼優化後結果變了?」 | 研讀 C 標準、C陷阱與缺陷、編譯器優化原理 |
| L4 匯編映射 | 看 C 代碼能腦補對應匯編(函數調用約定、寄存器分配、循環展開、向量化) | 「這段代碼編譯後大概幾條指令?」 | 學匯編、用 gcc -S -O2 看輸出、Godbolt Compiler Explorer |
| L5 系統級工程 | 設計無鎖數據結構、自定義分配器、JIT 編譯器、OS 內核模組、編譯器後端 | 「如何在 100ns 內完成一次內存分配?」 | 實戰高性能項目、閱讀 Linux/Redis/LevelDB 源碼 |
// 指針 = 內存地址(整數)+ 類型信息(編譯期用於解引用、算術、安全檢查)
int *p = &a; // p 存儲 a 的地址,類型 int* 告訴編譯器:*p 訪問 4 字節、p+1 偏移 4 字節
int **pp = &p; // 二級指針:存儲一級指針的地址,*pp 類型 int*,**pp 類型 int
// 關鍵認知:
// 1. 指針本身佔固定大小(32位 4B,64位 8B),與指向類型無關
// 2. 解引用 *p = 編譯器生成「讀/寫 p 所指地址」的機器指令
// 3. 指針算術 p + i = p + i * sizeof(*p),類型決定步長
// 4. void* = 只有地址無類型,不可解引用/算術,需強轉後使用
// 5. 野指針/懸空指針 = 地址值合法但指向內容已失效(栈帧銷毀、free 後、返回局部變量地址)
// C 代碼
int add(int a, int b) { return a + b; }
// x86-64 System V ABI 對應匯編 (gcc -O2 -S)
add:
mov eax, edi ; 參數 a 在 edi,返回值在 eax
add eax, esi ; 參數 b 在 esi,eax += esi
ret ; 返回
// 關鍵對應:
// 變量 → 寄存器/棧槽
// 表達式 → ALU 指令序列
// 控制流 → 跳轉/條件跳轉指令
// 函數調用 → 棧幀佈局、調用約定、返回地址
// 數組/結構體 → 基址+偏移寻址模式
**最高境界**:看到 for (i=0; iSIMD 向量化加載、計算、存儲 的指令流,並預判編譯器是否會自動向量化、是否需要 restrict/pragma 輔助。
malloc/free(隱式鏈表/顯式鏈表/伙伴系統),體會內存管理本質。C 語言**不深在語法**(關鍵字 32 個),**深在「抽象層極薄」**:
寫 a[i] 就是 *(a+i) 就是 base + i*stride 就是 MOV [RAX+RCX*4], RDX。
**看透這層映射,C 就沒有秘密**。剩下的只是工程經驗、領域知識、審美品味的積累。