1.C語言聲明的單獨語法成份
聲明器是C語言聲明的非常重要成份,他是所有聲明的核心內容,簡單的說:聲明器就是標識符以及與它組合在一起的任何指針、函數括號、數組下表等,為了方便起見這裡進行分類表示。
1)指針
(1)*
(2)* const
(3)* volatile
(4)* const volatile
(5)* volatile const
2)直接聲明器
(1)標識符
(2)標識符[下表]
(3)標識符(參數)
(4)(聲明器)
3)初始化內容
(1)= 初始值
C語言中的完整聲明包括的內容如下:
1)類型說明符:包括存儲類型和類型限定符
2)聲明器(見上面)
3)更多的聲明器
4)分號
注意:不是上面的所有組合都是合法的,如:你不能像這樣聲明foo()()、foo()[]。
2.優先級規則
上面說明C語言中聲明的各個組成部分,要理解一個聲明必須要動的其中的優先級規則,可以簡潔的以下面形式來直觀的反應這個規則:
A 聲明從他的名字開始讀取,然後按照優先級順序依次讀取
B 優先級從高到低依次是:
(1)聲明中被括號括起來的部分
(2)後綴操作符:括號()表示這是個函數,而方括號[]表示這是一個數組
(3)前綴操作符:星號*表示"指向...的指針"
C 如果const和(或)volatile關鍵字的後面緊跟類型說明符(如:int, long等),那麼它作用於類型說明符;否則其它情況下作用於它左邊緊鄰的指針星號。
const char *p; /* 常量指針 */
char const *p; /* 同上 */
char * const p; /* 指針常量 */
3. 舉例說明
(1)用優先級規則分析C語言聲明一例:
char * const *(*next)();
下面使用優先級規則解決這個聲明:
A 首先,看變量名"next",並注意到它直接被括號所擴住
B.1 所以先把括號裡得東西作為一個整體,得出"next是一個指向...的指針"
B 然後考慮括號外面的東西,在星號前綴和括號後綴之間做出選擇
B.2 該規則告訴我們優先級較高的是右邊的函數括號,所以得出“next是一個函數指針,指向一個返回...的函數”
B.3 然後,處理前綴“*”,得出指針所指的內容
C 最後把“char * const”解釋為指向字符的常量指針
上述的分析結果可以概括為:這個聲明表示next是一個指針,它指向一個函數,該函數返回一個指針,該指針指向一個類型為char的常量指針。
(2)分析C語言聲明二例:
int *(*p[])();
A 首先,看變量名"p",並注意到它直接被括號所擴住
B.1 所以先把括號裡得東西作為一個整體,得出"p是一個指向...的指針數組"
B 然後考慮括號外面的東西,在星號前綴和括號後綴之間做出選擇
B.2 該規則告訴我們優先級較高的是右邊的函數括號,所以得出“p是一個指向函數指針數組的指針,數組的每一個元素返回值是...的函數”
B.3 然後,處理括號外的前綴“*”,得出指針所指的內容
C 最後把“int *”解釋為指向整形的指針
上述的分析結果可以概括為:這個聲明表示p是一個指針,它指向一個函數指針數組,數組中每一個元素的形參為空,返回類型為指向一個類型為int指針。
(3)分析C語言聲明三例:
void (*signal(int sig,void(*func)(int)))(int);
乍一看,這是一個很嚇人的聲明,不過掌握了前面的優先級規則,再分析這個聲明就簡單的多了:
A 首先,看變量名"signal",並注意到它直接被括號所擴住
B.1 所以先把括號裡得東西作為一個整體,得出"signal是一個指向...的函數指針,有形參有返回值,返回值是一個指向...的指針"
B 然後考慮括號外面的東西,在星號前綴和括號後綴之間做出選擇,顯然括號外面的東西就是signal的返回值
B.2 該規則告訴我們優先級較高的是右邊的函數括號,所以得出“signal的返回值也是一個指向...的函數指針”
B.3 然後,括號外沒有"*"前綴
C 沒有符合的情況
上述的分析結果可以概括為:這個聲明表示signal是一個指針,它指向一個函數,該函數的形參為int和一個函數指針void(*func)(),返回類型也為一個函數指針,該函數的形參int,返回值為void。
掌握了這個方法,碰到再復雜的C聲明語句都能輕松搞定了。