天天看點

C/C++:如何了解複雜的聲明

http://blog.chinaunix.net/u/12783/showart_378340.html

C/C++:如何了解複雜的聲明

這裡說的聲明,不光适用于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.

本文可以用于除商業外的所有用途。此處“用途”包括(但不限于)拷貝/翻譯(部分或全部),不包括根據本文描述來産生代碼及思想。若用于非商業,請保留此 權利聲明,并标明文章原始位址和作者資訊;若要用于商業,請與作者聯系([email protected]),否則作者将使用法律來保證權利。