C 語言允許指針、陣列、函數任意嵌套組合,產生極難閱讀的聲明。右左法則是一種機械化解讀步驟,源自 C 標準的聲明規則逆向歸納:
從未定義的標識符開始,先向右,再向左;遇到括號反向;解析完括號內容跳出;重複直到結束。
注意:起點是未定義的標識符(如 func),而非最內層括號,因為聲明中可能有多個標識符,但被聲明的只有一個。
int (*func)(int *p);
func() → func 是函數* → func 是指針func 是函數指針,指向「參數為 int*、返回 int」的函數int (*func)(int *p, int (*f)(int*));
func:函數指針,參數 1:int*,參數 2:函數指針(參數 int*,返回 int),返回 intf:同理,函數指針,參數 int*,返回 intint (*func[5])(int *p); // func 是陣列,元素是函數指針
int (*(*func)[5])(int *p); // func 是指針,指向「含 5 個函數指針的陣列」
關鍵:[] 優先級高於 *,func[5] 先結合,故第一個是「函數指針陣列」,第二個是「指向陣列的指針」。
int (*(*func)(int *p))[5];
func 是函數指針int*,返回 指向「含 5 個 int 的陣列」的指針
int func(void) [5]; // 錯誤:函數不能返回陣列(陣列名是右值,無法接收)
int func[5](void); // 錯誤:陣列元素不能是函數(函數大小不固定,違反陣列元素等長要求)
練習 1:int (*(*func)[5][6])[7][8];
func是指針 → 指向 5×6 二維陣列 → 陣列元素是指針 → 指向 7×8 二維陣列
typedef int (*PARA)[7][8];
typedef PARA (*func)[5][6];
練習 2:int (*(*(*func)(int *))[5])(int *);
func是函數指針 → 參數int*→ 返回指針 → 指向含 5 個函數指針的陣列 → 函數指針參數int*返回int
typedef int (*PARA1)(int*);
typedef PARA1 (*PARA2)[5];
typedef PARA2 (*func)(int*);
練習 3:int (*(*func[7][8][9])(int*))[5];
func是 7×8×9 三維陣列 → 元素是函數指針 → 參數int*→ 返回指針 → 指向含 5 個 int 的陣列
typedef int (*PARA1)[5];
typedef PARA1 (*PARA2)(int*);
typedef PARA2 func[7][8][9];
實際工程中嚴禁直接書寫複雜指針聲明。應採用 typedef 逐層剝離:
// 原始難讀聲明
int (*(*func)(int *p))[5];
// 分解後清晰明瞭
typedef int (*ArrayPtr)[5]; // 指向 5-int 陣列的指針
typedef ArrayPtr (*FuncPtr)(int *p); // 返回 ArrayPtr 的函數指針
FuncPtr func; // 最终声明简洁清晰
這不僅提升可讀性,更便於維護與團隊協作。右左法則是「讀懂」舊代碼的工具,typedef 分解才是「寫出」好代碼的正道。