【譯】C語言「右左規則」
• C
這篇筆記、翻譯自博文:C Right-Left Rule,作者Rick Ord。尊重他人勞動果實,轉載請註明!
「右左」規則是解讀C宣告十分實用的規則。創建宣告時它也同樣有用。
首先,符號。在宣告中,視
* 為「指向 的指標」 通常在左邊
[] 為「 的陣列」 通常在右邊
() 為「返回 的函式」 通常在右邊
第一步
----------
找到標識符。這是初始點。然後妳知道,這個宣告是:「標識符是 」。
第二步
----------
查看標識符右邊的符號,如果是「()」,那就表示這是一個函式宣告:「標識符是返回 的函式」。抑或是「[]」,則是「標識符是 的陣列」。繼續查看右邊,直到沒有符號或者遇到一個右圓括號「)」。(如果遇到左圓括號,那是符號()的起始,即使括號間還有東西。更多以下詳解。)
第三步
----------
查看標識符左邊的符號。如果不是上面說的符號(比如「int」),直接代到句子裏面。否則,使用上述表格轉譯成文字。繼續查看左邊,直到沒有符號或者遇到左圓括號「(」。
接下來重複第二步和第三步,直到宣告解讀完畢。以下是一些範例:
int *p[]; 1)找到標識符。 int *p[] ^ 「p是 」 2)向右邊移動,直到沒有符號或者遇到右圓括號。 int *p[] ^^ 「p是 的陣列」 3)不能再向右邊移動了(沒有符號),因而向左邊移動並得到: int *p[] ^ 「p是指向 的指標的陣列」 4)繼續向左邊移動並得到: int *p[] ^^^ 「p是指向int的指標的陣列」 (或者「p是一個陣列,其元素型別為指向int的指標」)
另一個範例:
int *(*func())(); 1)找到標識符。 int *(*func())(); ^^^^ 「func是 」 2)向右邊移動。 int *(*func())(); ^^ 「func是返回 的函式」 3)遇到右圓括號,不能再向右邊移動了,因而向左邊移動: int *(*func())(); ^ 「func是返回指向 的指標的函式」 4)遇到左圓括號,不能再向左邊移動了,因而繼續向右邊移動: int *(*func())(); ^^ 「func是返回指向返回 的函式的指標的函式」 5)沒有符號,不能再向右邊移動了,因而轉向左邊: int *(*func())(); ^ 「func是返回指向返回指向 的指標的函式的指標的函式」 6)最後,因為右邊沒有了,繼續向左邊移動。 int *(*func())(); ^^^ 「func是返回指向返回指向int的指標的函式的指標的函式」
正如妳所看到的,這個規則相當有用。妳也可以在創建宣告時用它來做完整性檢查,或提示下一個符號的位置以及括號是否必要。
有些宣告因原型中陣列長度和參數列表而看起來比實際複雜得多。如「[3]」,意為「__的(長度為3的)陣列。又如「(char *,int)」,意為「參數為(char *,int),返回__的函式」。來一個比較有趣的:
int (*(*fun_one)(char *,double))[9][20];
這裡就不詳細羅列解讀過程,直接揭曉答案:
「fun_one是指向參數為(char *,double)並返回指向int陣列(長度為20)的陣列(長度為9) 的指標的函式的指標。」
正如妳所看到的,去掉陣列長度和參數列表後,其實並不復雜:
int (*(*fun_one)())[][];
妳可以先這樣解讀,然後再添上陣列長度和參數列表。
結語:
使用這個規則很有可能做出非法宣告,因而關於什麼在C中是合法的基本常識是必要的。例如,如果把上述語句寫作:
int *((*fun_one)())[][];
這樣就解讀為「fun_one是指向返回指向int的指標的陣列的陣列的函式的指標」。因為函式不能返回陣列,而是指向陣列的指標,因而這樣宣告是非法的。
非法的組合還有:
[]() - 不存在函數陣列 ()() - 不存在返回函式的函式 ()[] - 不存在返回陣列的函式
在以上所有情況下,為了使宣告合法,妳需要用一對括號去結合左邊*符號和右邊()和[]間的符號。
以下是一些合法和非法的例子:
int i; int的變數 int *p; int的指標(指向int的指標) int a[]; int的陣列 int f(); 返回int的函式 int **pp; 指向int的指標的指標 int (*pa)[]; 指向int的陣列的指標 int (*pf)(); 指向返回int的函式的指標 int *ap[]; int的指標的陣列(指向int的指標的陣列) int aa[][]; int的陣列的陣列 int af[](); 返回int的函式的陣列(非法) int *fp(); 返回int的指標的函式 int fa()[]; 返回int陣列的函式(非法) int ff()(); 返回返回int的函式的函式(非法) int ***ppp; 指向指向int的指標的指標的指標 int (**ppa)[]; 指向指向int的陣列的指標的指標 int (**ppf)(); 指向指向返回int的函式的指標的指標 int *(*pap)[]; 指向int的指標的陣列的指標 int (*paa)[][]; 指向int的陣列的陣列的指標 int (*paf)[](); 指向返回int的函式的陣列的指標(非法) int *(*pfp)(); 指向返回int指標的函式的指標 int (*pfa)()[]; 指向返回int的陣列的函式的指標(非法) int (*pff)()(); 指向返回返回int的函式的函式的指標(非法) int **app[]; 指向int指標的指標的陣列 int (*apa[])[]; 指向int的陣列的指標的陣列 int (*apf[])(); 指向返回int的函式的指標的陣列 int *aap[][]; int指標的陣列的陣列 int aaa[][][]; int的陣列的陣列的陣列 int aaf[][](); 返回int的函式的陣列的陣列(非法) int *afp[](); 返回int指標的函式的陣列(非法) int afa[]()[]; 返回int的陣列的函式的陣列(非法) int aff[]()(); 返回返回int的函式的函式的陣列(非法) int **fpp(); 返回指向int指標的指標的函式 int (*fpa())[]; 返回指向int的陣列的指標的函式 int (*fpf())(); 返回指向返回int的函式的指標的函式 int *fap()[]; 返回int指標的陣列的函式(非法) int faa()[][]; 返回int的陣列的陣列的函式(非法) int faf()[](); 返回返回int的函式的陣列的函式(非法) int *ffp()(); 返回返回int指標的函式的函式(非法)