c函數聲明 左右法則

左右法則

刺蝟@http://blog.csdn.net/littlehedgehog

 



關於Linux內核中有一個關於signal函數的聲明,如下:

 

void (*signal(intvoid (*_func)(int)))(int);

 

c語言聲明繁雜一直被人認爲是C的詬病,大家從這個函數可見一斑。還好有前輩專門針對此提出了個“左右法則”。大家不妨讀讀:

 

上一章費那麼多脣舌討論C語言的聲明,其實目的都是爲了這一章,期望讀者通過對C語言聲明形式的詳細瞭解,樹立聲明嵌套的觀念,因爲C語言所有複雜的指針聲明,都是由各種聲明嵌套構成的。如何解讀複雜指針聲明呢?右左法則是一個既著名又常用的方法。不過,右左法則其實並不是C標準裏面的內容,它是從C標準的聲明規定中歸納出來的方法。C標準的聲明規則,是用來解決如何創建聲明的,而右左法則是用來解決如何辯識一個聲明的,兩者可以說是相反的。右左法則的英文原文是這樣說的:

The right-left rule: Start reading the declaration from the innermost parentheses, go right, and then go left. When you encounter parentheses, the direction should be reversed. Once everything in the parentheses has been parsed, jump out of it. Continue till the whole declaration has been parsed.


這段英文的翻譯如下:

右左法則:首先從最裏面的圓括號看起,然後往右看,再往左看。每當遇到圓括號時,就應該掉轉閱讀方向。一旦解析完圓括號裏面所有的東西,就跳出圓括號。重複這個過程直到整個聲明解析完畢。

        筆者要對這個法則進行一個小小的修正,應該是從未定義的標識符開始閱讀,而不是從括號讀起,之所以是未定義的標識符,是因爲一個聲明裏面可能有多個標識符,但未定義的標識符只會有一個。

現在通過一些例子來討論右左法則的應用,先從最簡單的開始,逐步加深:

int (*func)(int *p);

首先找到那個未定義的標識符,就是func,它的外面有一對圓括號,而且左邊是一個*號,這說明func是一個指針,然後跳出這個圓括號,先看右邊,也是一個圓括號,這說明(*func)是一個函數,而func是一個指向這類函數的指針,就是一個函數指針,這類函數具有int*類型的形參,返回值類型是int。

int (*func)(int *p, int (*f)(int*));

func被一對括號包含,且左邊有一個*號,說明func是一個指針,跳出括號,右邊也有個括號,那麼func是一個指向函數的指針,這類函數具有int *和int (*)(int*)這樣的形參,返回值爲int類型。再來看一看func的形參int (*f)(int*),類似前面的解釋,f也是一個函數指針,指向的函數具有int*類型的形參,返回值爲int。

int (*func[5])(int *p);

func右邊是一個[]運算符,說明func是一個具有5個元素的數組,func的左邊有一個*,說明func的元素是指針,要注意這裏的*不是修飾func的,而是修飾func[5]的,原因是[]運算符優先級比*高,func先跟[]結合,因此*修飾的是func[5]。跳出這個括號,看右邊,也是一對圓括號,說明func數組的元素是函數類型的指針,它所指向的函數具有int*類型的形參,返回值類型爲int。


int (*(*func)[5])(int *p);

func被一個圓括號包含,左邊又有一個*,那麼func是一個指針,跳出括號,右邊是一個[]運算符號,說明func是一個指向數組的指針,現在往左看,左邊有一個*號,說明這個數組的元素是指針,再跳出括號,右邊又有一個括號,說明這個數組的元素是指向函數的指針。總結一下,就是:func是一個指向數組的指針,這個數組的元素是函數指針,這些指針指向具有int*形參,返回值爲int類型的函數。

int (*(*func)(int *p))[5];

func是一個函數指針,這類函數具有int*類型的形參,返回值是指向數組的指針,所指向的數組的元素是具有5個int元素的數組。

要注意有些複雜指針聲明是非法的,例如:

int func(void) [5];

func是一個返回值爲具有5個int元素的數組的函數。但C語言的函數返回值不能爲數組,這是因爲如果允許函數返回值爲數組,那麼接收這個數組的內容的東西,也必須是一個數組,但C語言的數組名是一個右值,它不能作爲左值來接收另一個數組,因此函數返回值不能爲數組。

int func[5](void);

func是一個具有5個元素的數組,這個數組的元素都是函數。這也是非法的,因爲數組的元素除了類型必須一樣外,每個元素所佔用的內存空間也必須相同,顯然函數是無法達到這個要求的,即使函數的類型一樣,但函數所佔用的空間通常是不相同的。

 

以上文章摘自http://blog.csdn.net/megaboy/archive/2005/09/17/482771.aspx

那麼接下來看看

void (*signal(intvoid (*_func)(int)))(int);

 1、signal往右看:是一串的參數(int, void (*_func)(int)),可以看出signal是一個函數,函數纔可以帶參數;
2、signal往左看:是一個星號*,表示返回值是一個指針,但是沒有說明具體什麼類型的指針,好,我們接着往下看;
3、(*signal(int, void (*_func)(int)))往右看:是一個參數:(int);
4、(*signal(int, void (*_func)(int)))往左看:是一個void;
5、OK,那麼上面兩個用來限定誰?顯然,用來限定第二步我們看到的*號,OK,一個指針可以帶參數,又有返回類型(void),那肯定是一個函數指針;

好了,到這裏我們分析完畢,可以得出:
signal是一個帶2個參數(int, void (*_func)(int)),返回值爲函數指針(指向參數爲int類型,返回值爲void的函數)的函數。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章