Linux 核心由 C 語言與少量組合語言編寫而成。面對這龐大的系統,C 語言作為一門面向過程的語言,沒有內建的「類別」或「物件」概念,卻必須保證系統架構的清晰與正確性。關鍵在於 C 語言擁有一個更靈活的工具——結構體。它身經百戰、能屈能伸,在核心程式碼中無處不在,扮演著「物件」的角色,將資料與操作有機結合。
結構體顧名思義是用來結構化組織資料的。但物件導向的核心是「封裝」——資料與操作資料的函數必須綁在一起。C 語言雖無封裝機制,卻有強大的指標。熟練運用指標能帶來數量級的效率提升,雖然指標的不安全性是 Java 等語言捨棄它的原因,但指標正是 C 語言的基本資料結構之一。結構體正是用來組織基本資料結構(包含指標),形成滿足應用需求的封裝結構。
更關鍵的是,C 支援函數指標。因此,結構體完全可以包含函數指標作為成員,以此封裝資料相關的操作。這樣一來,C 語言在語言層面就實現了對「物件」這一資料結構的抽象,威力驚人。
瞭解結構體的強大之處後,我們必須掌握其應用精髓。既然結構體涉及基本資料結構的組織與封裝,勢必牽涉到記憶體分配與位元組對齊。為了讓程式達到最優效能,結構體中的位元組對齊問題不容忽視。建議參考專文《位元組對齊》深入學習,這將是你從「小白」進階為高手的必經之路。
在所有運算子中,結構體成員存取運算子 . 和 ->、函數呼叫運算子 () 以及下標運算子 [] 優先級最高,它們與運算元的結合最緊密。這一規則若掌握不透,極易寫出語義錯誤的程式碼。以下以指向結構體的指標 p 為例說明:
struct {
int len;
char *str;
} *p;
| 表達式 | 隱含括號關係 | 語義說明 |
|---|---|---|
++p->len | ++(p->len) | 增加 len 的值 |
(++p)->len | (++p)->len | 先執行 p 的加 1 操作,再取 len 的值 |
(p++)->len | (p++)->len | 先取 len 的值,再執行 p 的加 1 操作 |
*p->str | *(p->str) | 取指標 str 所指向的對象的值 |
*p->str++ | *(p->str++) | 先取指標 str 所指向的對象的值,然後將 str 加 1 |
(*p->str)++ | (*(p->str))++ | 先取指標 str 所指向的對象的值,然後將對象值加 1 |
*p++ ->str | *(p++) ->str | 先取指標 str 所指向的對象的值,然後將 p 值加 1 |
這些優先級規則看似枯燥,卻是寫出正確、高效核心程式碼的基石。熟練掌握它們,才能在 Linux 核心開發的浩瀚海洋中駕輕就熟。