對於復雜的C函數聲明,或者被typedef別名後的聲明,很多人往往一頭霧水。本文主要解析下C語言中聲明過程所遵循的原則。
引用《C專家編程》的第三章內容,說明下聲明的優先級規則:
不過,我覺得這個規則的不夠通俗,看了《C++Annotation》中關於const的那一章節,也詳細解釋了下這個規則,高效,庖丁解牛般分析:
char* const *(*next)();
解釋,就是從變量名開始,碰到)或結束往左讀,碰到(往右讀。
及
指向什麼類型
讀,碰到了, ( ,解釋是一個指針 繼續往左讀碰到, (* 遇到,解釋指向一個函數,該函數沒有形參 到,
(*,解釋函數返回一個指針,關於函數的形參表和返回值解釋完畢 , *(*next)() 先碰到const,再是*, 最後是char, 解釋函數的返回值(指針)指向一個char型指針常量,即指針不可賦新值,所指的值可以改變。到開頭,結束。
以上的例子是函數的聲明舉例。
對其他的聲明也是一樣的,比如之前文章中 int *ap[], 我們也是這樣解釋的:
常規的 const int * p; 也可以這麼來:
同理,對於 int* const p: 我們在往左看時,先看到了const,再*, 說明const修飾的是*。
來個復雜的挑戰下吧:
* * (* (*(** ip是一個函數指針,該函數無形參 (* 該指針指向一個數組 * 該常量指針指向一個數組
不過,一般不會有這種聲明來惡心我們的。。我們基本上知道怎麼打就行了。
剖析完了聲明,一般來說還要說下 typedef ,這可是C的一大神器呀。
首先,我們要明確的是,typedef是為類型創建別名,而不是創造新的類型。
講typedef時,又必須和 #define做下區分, define僅是簡單的宏擴展
主要來說,有以下的區別:
INT int unsigned tInt tci;
pD int** pT c,d;
和typedef做好朋友
void (*signal(int sig, void(*func)(int))) (int);
我們來分析下這個是什麼東西:
signal(..) : signal 是一個函數,有復雜的形參表
*signal(...) : 返回值是一個指針
: 該指針指向一個函數,該函數的形參為int, 這個函數的返回值是void
我們看看signal的形參表: 兩個參數,一個參數是 int; 另外個參數 是一個函數指針,該函數有一個int形參,返回void;
對比下,我們可以分析出, signal的返回值和 func的定義一樣, 都是 void(*)(int), 但若是采用這種寫法的話,不好看懂,這時候,我們的好朋友typedef就出現了:
typedef (*ptr_to_func)(, ptr_to_func){.....}
另外,typedef也經常和struct配合使用。
typedef my_struct{....} NewName;
這樣,NewName 就等同於 struct my_struct , 少打了struct這幾個字符
擴展說下 聲明和定義的區別:
C語言中,對象,而聲明卻可以有。
定義:只能出現在一個地方,確定同時分配內存,它是特殊的聲明
聲明:只是其他地方創建對象的。有extern前綴,作用於變量
具體的一些擴展區別,見後續博文,關於指針和數組的闡釋
END
要點: 怎麼打乒乓?typedef是個別名好朋友