這裏說的聲明,不光適用於C/C++,其他的一些語言也能適用。
與java和C#等不同,聲明和定義在C/C++中有著比較明顯的區別:聲明僅僅是介紹名字(introduce names),而定義則會為該名字分配相應的空間。打個通俗的比喻:聲明就是你在談話中提到某個人的名字,而定義就是把你提到的這個人帶到談話的人群中來,讓大家見識一下他/她是什麼樣子。
這裏主要介紹聲明。
在C中,聲明的形式為(dcl是declaration的簡寫):
dcl: optional *'s direct-dcl(含有可選"*"的direct-dcl)
direct-dcl name
(dcl)
direct-dcl()
direct-dcl[optional size]
根據該規則進行逆向解析,就可以得到正確的聲明。簡化一下:“TypeName Declarator;”其中,Declarator就是聲明中的那個名字。當你遇到任何你不能理解的聲明時,這個法則就是救命稻草。最簡單的例子:
int aInt;
這裏,int是TypeName,aInt是Declarator。
再說明一下結合緊密度。在聲明/定義變量時,可以使用一些修飾比如“*”,“[]”,“()”等。“()”(非函數聲明中的“()”)具有最高的緊密度,其次才是函數和數組的“()”和“[]”。
沒有“*”的聲明稱為直接聲明(direct-dcl),而有“*”稱為聲明(dcl)。直接聲明要比聲明結合的緊。分解聲明時,先讀出結合緊的。在這裏,我把direct-dcl稱為更緊的結合,它比dcl結合得緊。
最後,需要你用英語來讀出這個聲明。對於“[]”,應該讀成array of。
對於複雜的定義,可以將其分解。比如“T (*p)()”可以分解成“T D1()”,D1讀作:function returning T。其中D1是*p。那麼該聲明應該讀成:p is a poniter to。二者合在一起,就變成了p is a pointer to function returning T,即:p是指向返回T類對象的函數的指針。
再看一個稍微複雜的示例:
T (*pfa[])();
根據dcl和direct-dcl,可以分解成T1 D1(因為結合緊密度),T1, 也就是T (),那麼應該讀作:
D1 is function returning T。
D1又可以寫成T2 D2,其中T2是T1 [],可以分解成T1 D2[],讀作:
array of D2 function returning T。
D2是指針,讀作:pointers to。那麼整個“T (*pfa[])();”應該讀作:
pfa is an array of pointers to function returning T,即:pfa是個存放指向返回T類對象函數的指針的數組。
換種方式看,在這個例子中,pfa是名字,T(*[])()是類型。將(*pfa[])視為一體(direct-dcl),稱為D1,那麼可以寫成T D1(),function returning object of T。在D1中,將*pfa視為一體(dcl),稱為D2,那麼*pfa[]應該是D2[](direct-dcl),array of D2。合起來就是array of D2 function returning object of T。D2是*pfa(dcl),替換到前麵這句話,結果就是array of pointers to function returning object of T。
有了這些說明,可以試著做一下下麵的題,看看自己是否真的理解了:
char **argv
argv: pointer to pointer to char
int (*daytab)[13]
daytab: pointer to array[13] of int
int *daytab[13]
daytab: array[13] of pointer to int
void *comp()
comp: function returning pointer to void
void (*comp)()
comp: pointer to function returning void
char (*(*x())[])()
x: function returning pointer to array[] of
pointer to function returning char
char (*(*x[3])())[5]
x: array[3] of pointer to function returning
pointer to array[5] of char
有了這個,就很容易理解下麵這兩個typedef:
typedef void (*disp)(int);
typedef void (*signal(int, disp))(int);
在C++中,規則比C要複雜一些。不過,基本思想保持不變,按照C的原則來理解複雜的聲明,基本上就能滿足要求了。沒有在這裏列出C++的規則一方麵是因為太廣,不能覆蓋全;另一個原因就是,按照C的規則來就足夠了,畢竟C++要與C兼容。
這裏討論的僅僅是聲明,不涉及到類型的signature,因此相對來說還是比較簡單的。
參考:
The C programming Language, by Brian W. Kernighan and Dennis M. Ritchie
The C++ programming Language, by Bjarne Stroustup
Copyleft (C) 2007-2009 raof01.
本文可以用於除商業外的所有用途。此處“用途”包括(但不限於)拷貝/翻譯(部分或全部),不包括根據本文描述來產生代碼及思想。若用於非商業,請保留此 權利聲明,並標明文章原始地址和作者信息;若要用於商業,請與作者聯係(raof01@gmail.com),否則作者將使用法律來保證權利。