右左法則是一個既著名又常用的方法。不過,右左法則其實並不是C標準裡面的內容,它是從C標準的聲明規定中歸納出來的方法。C標準的聲明規則,是用來解決如何建立聲明的,而右左法則是用來解決如何辯識一個聲明的。
右左法則:首先從最裡面的圓括弧看起,然後往右看,再往左看。每當遇到圓括弧時,就應該掉轉閱讀方向。一旦解析完圓括弧裡面所有的東西,就跳出圓括弧。重複這個過程直到整個聲明解析完畢。
筆者要對這個法則進行一個小小的修正,應該是從未定義的標識符開始閱讀,而不是從括弧讀起,之所以是未定義的標識符,是因為一個聲明裡面可能有多個標識符,但未定義的標識符只會有一個。
要理解比較複雜的指標型別宣告,在描述一個指標時就要注意語言比較簡明。下面是我的一些規則。
描述一個數組時:int a[5] a是一個且有5個元素的數組,它的元素是int型變數
描述一個函數指標時:int (*p)(int i) p是一個函數指標,這類函數且有int型傳回值,且有一個int型參數
int (*func)(int *p);
。從func看起,向左到括弧,向右為*,結果:func為一個指標
。跳出括弧,向右看,又是一個括弧。結果:func為一個指標函數
。向左為int 結果:func為一個函數指標,這類函數且有一個int*型參數,且有一個int型傳回值。
int (*func)(int *p, int (*f)(int*));
。從func看起,向左到括弧,向右為*,結果:func為一個指標
。跳出括弧,向右看,又是一個括弧。結果:func為一個指標函數
。向左為int 結果:func為一個函數指標,這類函數且有一個int (*f)(int*)參數,且有一個int型傳回值。
。第二個參數較複雜,單獨來看,可以發現與上面的例子一樣。
int (*func[5])(int *p);
。從func看起,向左為[5],結果:func為一個且有5個元素的數組。
。向右為*,結果:數組的元素為指標
。跳出括弧,向右看,又是一個括弧。結果:數組的元素是一個指標數組
。向左為int 結果:func是一個且有5個元素的數組,數組的元素為一個函數指標,這類函數且有int型傳回值,且有一個int*型參數。
說明:因為第一次向右看即為數組,說明func是數組,這裡已經固定func的類型,下面再說即是對數組元素的描述
int (*(*func)[5])(int *p);
。從func看起,向左到括弧,向右為*,結果:func為一個指標
。跳出括弧,向右看,是一個[5],說明func是一個數組指標,指向一個且有5個元素的數組。
。向左看,是一個*,說明數組的元素是指標。
。跳出括弧,向右看,是一個括弧,說明數組的元素是函數指標
。向左為int 結果:func為一個指向且有5個元素的數組的指標,數組的元素是一個函數指標,這類函數且有int型傳回值,且有一個int*型參 數
說明:這裡從指標跳到數組元素,再從數組元素跳到函數指標,一層層的說明。更容易理清條理
int (*(*func)(int *p))[5];
。從func看起,向右為括弧,向左為*,說明func是一個指標
。跳出括弧向右為一個括弧,說明func是一個函數指標,這類函數且有int*型參數
。向左為一個*,說明這類函數返回指為一個指標
。向右為[5],說明這類函數傳回值為數組指標
。向左為一個int,說明數組且有5個int型元素
。func是一個函數指標,這類函數且有一個int*型參數。傳回值為數組指標,數組裡有5個int型元素
說明:當確定為數組後,馬上進入數組元素的分析
當確定為函數指標後,馬上進入對函數的分析,函數類型、函數傳回值
當確定為數組指標後,馬上進入它所指向數組的分析
實際應用中這樣聲明複雜的類型大大影響程式的可讀性。應該分解,比如:
int (*(*func)(int *p))[5];
可以分解為:
typedef int (*PARA)[5];
PARA (*func)(int *p);