void (*b[10]) (void (*)());

void (*b[10]) (void (*)());

看到這行代碼,相信程序員們都會倒吸一口冷氣吧。如果非常不幸的在維護的代碼中看到類似的表述,除了想辦法找出寫出這種天書的猛人來,只能自己硬著頭皮搞清楚了。

在C和C++中,構(gòu)造這類聲明表達式只有一條簡單的規(guī)則:按照使用的方式來聲明。

C變量的聲明都是由兩部分組成的:類型,以及一組類似表達式的聲明符(declarator)。聲明符類似于表達式,對它求值應該返回一個聲明中給定類型的結(jié)果。例如,我們來看一個簡單的聲明:

float f;

這里f就是聲明符,對其求值,應該得到一個float型的數(shù)值。

然后看括號的作用,比如:

float ((f));

很簡單,這個聲明的含義就是,((f))的類型為浮點類型。因為括號和f之間沒有其他的修飾了,所以,我們可以推知,f也是浮點型。

再來看稍微復雜點的:

float f();

我們注意到有一個()表達式出現(xiàn),這個聲明符的含義是一個函數(shù)。所以這個聲明的含義就是,f()的求值結(jié)果是一個浮點數(shù),也就是說,f是個返回值為浮點數(shù)的函數(shù)。

OK,這些都很簡單,再看一個:

float *f();

這個就是表示f()是個浮點表達式,而()的結(jié)合優(yōu)先級高于,所以,f()也就是(f()),f是個函數(shù),返回值是個指針,這個指針指向一個浮點數(shù)。

如果*f是先結(jié)合的呢?比如:

float (*f)();

這時,f就不是和()結(jié)合而成為一個函數(shù)名,而是和*結(jié)合成為一個指針名,這個指針,是指向函數(shù)入口的函數(shù)指針,而這個函數(shù),返回值是浮點型。

現(xiàn)在我們知道怎么聲明一個指定類型的變量了。在這個聲明表達式中,把變量名,和聲明末尾的分號去掉,剩余的部分用一個括號整個括起來,這樣就得到了這個變量的類型聲明了,比如:

float (*f)();

這個表示f是一個指向返回值為浮點型的函數(shù)指針。而我們把f這個變量名,和最后的;號去掉,就得到:

( float (*)() )

這個就表示,這個表達式是一個類型,即“指向返回值為浮點型的函數(shù)的指針”。如果用這個類型去修飾一個變量名,我們就叫它類型轉(zhuǎn)換符。

現(xiàn)在有了這些預備知識,我們可以回頭看標題的聲明到底是什么意思了:

void (*b[10]) (void (*)());

首先,表達式的后半部分被兩個()分隔開了,我們分別分析它們。( *b[10] ),其中出現(xiàn)了變量名b,很容易就知道,b是一個有10個元素的數(shù)組,每個元素都是一個指針。

然后,看(void(*)()),其中沒有出現(xiàn)變量名,所以它代表了一個類型,即“指向返回值為void型的函數(shù)的指針“,而我們知道,C語法中,類型修飾符是必須出現(xiàn)在變量名的左邊的,而在整個表達式中這個類型符是在變量名b的右邊,所以, (void(*)())最外層的這個(),表示了定義了一個函數(shù),這個函數(shù)有一個參數(shù),就是一個指針,具體來說,就是“指向返回值為void型的函數(shù)的指針“。

這樣就很清楚了,b數(shù)組里,每一個指針元素,都是一個函數(shù)指針,這個函數(shù)有一個參數(shù),這個參數(shù)是一個函數(shù)指針。整個表達式最左邊的void,則定義了b數(shù)組中函數(shù)指針所指向函數(shù)的返回值類型。

在一串繞口令式的解說后,我們終于看到了事實的真相:這行代碼就是逗你玩...

如果不是故意偷懶,這樣代碼的作者真是在玩弄閱讀者的感情,如果非要實現(xiàn)這樣一個復雜的定義的話,我們也是有更好的方法的,就是使用typedef來進行類型聲明。

在面對void (*b[10]) (void (*)());時,我們可以先聲明后半部分的類型:

typdef void (*pFunParam)();

即表示,類型pFunParam,是一個函數(shù)指針。

然后,針對整個表達式聲明一個類型:

typedef void (*pFun)(pFunParam);

即表示,類型pFun,是一個函數(shù)指針。此函數(shù)的參數(shù)類型為pFunParam。

最后,進行變量的聲明:

pFun b[10];

這樣,就清晰許多了吧。最重要的時,利用這樣的方式,將編寫者的設(shè)計思路也體現(xiàn)在了代碼中。

最后,介紹一個更快速的閱讀方法:從右向左。

編譯器在進行代碼掃描時是從左向右的,而我們在解讀這個表達式的時候,從右向左的方法會更容易些,如:

從右向左掃描以上表達式,首先我們看到一個“)”,因為其右邊再沒有變量,所以我們知道這是一個函數(shù)定義,然后,又看到一對“()“,顯然也是函數(shù)定義,在就是(*),顯然和后面的()聯(lián)合起來表達了一個函數(shù)指針,再左邊的void,即修飾了此指針的類型;然后出現(xiàn)了和最右邊”)"對應的”(”,顯然這個函數(shù)定義也完成了,再左邊的[10]表達了一個數(shù)組,左邊是它的名字b,而更左邊的“*”和后面的“(“一起表達了一個函數(shù)指針,這個函數(shù)指針定義了b數(shù)組中元素的類型。再往左,指針元素的定義void也出現(xiàn)了。這樣,我們就又看到了此表達式的真相。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容