詳解C/C++函式指標宣告
要理解一個C程式,僅僅理解組成該程式的符號是不夠的。程式設計師還必須理解這些符號是如何組合成宣告、表示式、語句和程式的。
我們先來看看下面的一個語句:
1
|
(
*( void (*)())0)(); |
這是當計算機啟動時,硬體將呼叫首地址為0位置的子例程。像這樣的表示式恐怕會令每個C/C++程式設計師的內心都“不寒而慄”吧。
然而,完全不用害怕,任何C變數的宣告都是由兩部分組成:型別以及一組類似表示式的宣告符。最簡單的宣告變數,如:
1
|
float f
, g ; |
這個宣告的含義是:當對其求值時,表示式f和g的型別為浮點型。
同樣的邏輯也適用於函式和指標型別的宣告,例如:
1
|
float ff(); |
這個宣告的含義是:表示式ff()求值結果是一個浮點數,也就是說,ff是一個返回值為浮點型別的函式,類似地:
1
|
float *pf; |
這個宣告的含義是*pf是一個浮點數,也就是說,pf是一個指向浮點數的指標。
以上這些形式在宣告中還可以組合起來,就像在表示式中進行組合一樣,因此:
1
|
float *g()
, (*h)(); |
表示*g()與(*h)()是浮點表示式。因為()結合優先順序高於*,*g()也就是*(g()):g是一個函式,該函式的返回值型別為指向浮點數的指標。同理,可以得出h是一個函式指標,h所指向函式的返回值為浮點型別。
一旦我們知道了如何宣告一個給定型別的變數,那麼該型別的型別轉換符就很容易得到了:只需要把宣告中的變數名和宣告末尾的分號去掉,再將剩餘的部分用一個括號整個“封裝”起來即可。例如:
1
|
float (*h)(); |
表示h是一個指向返回值為浮點型別的函式的指標,因此,
1
|
( float (*)()) |
表示一個“指向返回值為浮點型別的函式的指標”的型別轉換符。
那麼,我們現在來看看前面我們提出的表示式:
1
|
(
*( void (*)())0)(); |
第一步,假定變數fp是一個函式指標,那麼如何呼叫fp所指向的函式呢?呼叫方法如下:
1
|
(*fp)(); |
因為fp是一個函式指標,那麼*fp就是該指標所指向的函式,所以(*fp)()就是呼叫該函式的方式。
表示式(*fp)()中,*fp兩側的括號非常重要,因為函式運算子()的優先順序高於單目運算子*。如果*fp兩側沒有括號,那麼*fp()實際上與*(fp())的含義完全一致。
現在剩下的問題就只是找到一個恰到的表示式來替換fp。我們將在分析的第二步來解決這個問題。如果C編譯器能夠理解我們大腦中對於型別的認識,那麼我們可以這樣寫:
1
|
(*0)() |
上式並不能生效,因為運算子*必須要一個指標來做運算元。而且這個指標還應該是一個函式指標,這樣經運算子*作用後的結果才能作為函式被呼叫。因此,在上式中必須對0作型別轉換,轉換後的型別可以大致描述為:“指向返回值為void型別的函式的指標”。
如果fp是一個指向返回值為void型別的函式的指標,那麼(*fp)()的值為void,fp的宣告如下:
1
|
viod
(*fp)(); |
因此,將常數0轉型為“指向返回值為void的函式的指標”型別,可以這樣寫:
1
|
( void (*)())0 |
因此,我們可以用(void(*)())0來替換fp,從而得到:
1
|
(
*( void (*)())0)(); |
當然,我們用typedef來解決這個問題能夠表述更加清晰:
1
2
|
typedef void (*fp)(); (*(fp)0)(); |
這個問題就可以解決了。
我們再來考慮signal庫函式,一般情況下,程式設計師並不主動宣告signal函式,而是直接使用標頭檔案signal.h中的宣告。那麼,在標頭檔案signal.h中,signal函式是如何宣告的呢?
首先,讓我們從使用者定義的訊號處理函式開始考慮,這無疑是最容易解決的。該函式可以定義如下:
1
2
3
|
void sigfunc( int n){ /*
特定訊號處理部分*/ } |
函式sigfunc的引數是一個代表特定訊號的整數值,此處我們暫時忽略它。
上面假設的函式體定義了sigfunc函式,因而sigfunc函式的宣告可以如下:
1
|
void sigfunc( int ); |
現在假定我們希望宣告一個指向sigfunc函式的指標變數,不妨命名為sfp。因而sfp指向sigfunc函式,*sfp就代表sigfunc函式,因此*sfp可以被呼叫。因此我們可以如下這樣宣告sfp:
1
|
void (*sfp)( int ); |
因為signal函式的返回值型別與sfp的返回值型別一樣,上式也就宣告瞭signal函式,我們不妨可以如下宣告signal函式:
1
|
void (* signal (something))( int ); |
此處的something代表了signal函式的引數型別,我們還需要進一步瞭解如何宣告它們。上面宣告可以這樣理解:傳遞適當的引數以呼叫signal函式,對signal函式返回值(為函式指標型別)解除引用,然後傳遞一個整型引數呼叫解除引用後所得函式,最後返回值為void型別。因此,signal函式的返回值是一個指向返回值為void型別的函式指標。
那麼,signal函式的引數又是如何呢?,signal函式接受兩個引數:一個整型的訊號編號,以及一個指向使用者定義的訊號處理函式的指標。我們此前一定定義了指向使用者定義的訊號處理函式的指標sfp:
1
|
void (*sfp)( int ); |
sfp的型別可以通過將上面的宣告中的sfp去掉而得到,即 void(*)(int)。此外,signal函式的返回值是一個指向呼叫前的使用者定義訊號處理函式的指標,這個指標的型別與sfp指標型別一致。因此我們可以如下宣告signal函式:
1
|
void (* signal ( int , void (*)( int )))( int ); |
同樣地,使用typedef可以簡化上面的函式宣告:
1
2
|
typedef
void (*HANDLER)(int); HANDLER
signal(int , HANDLER); |
那麼,現在的你對函式指標理解了嗎?如果你看完了此篇文章,相信你一定會有意想不到的收穫哦!
相關文章
- C++函式指標詳解C++函式指標
- c++ 函式指標C++函式指標
- C++(函式指標)C++函式指標
- [C++] 成員函式指標和函式指標C++函式指標
- 宣告與函式、函式指標函式指標
- C++ 智慧指標詳解C++指標
- C++中函式指標與函式物件C++函式指標物件
- 函式指標使用c++類成員函式函式指標C++
- c++ 類的函式引用 指標C++函式指標
- c++ 智慧指標用法詳解C++指標
- C/C++——指向函式的指標和指向函式的指標的陣列C++函式指標陣列
- 詳解c++指標的指標和指標的引用C++指標
- C++定義函式指標,回撥C#C++函式指標C#
- C++中的函式指標和函式物件總結C++函式指標物件
- 陣列,函式與指標 詳解陣列函式指標
- C# 跨平臺呼叫C++的函式指標C#C++函式指標
- 匿名函式(lambda)詳解 C++函式C++
- c++建構函式詳解C++函式
- 【不在混淆的C】指標函式、函式指標、回撥函式指標函式
- C++程式的函式指標:實操來了C++函式指標
- c++智慧指標中的reset成員函式C++指標函式
- C++ 成員函式指標簡單測試C++函式指標
- 宣告函式指標並實現回撥 (轉)函式指標
- c++建構函式詳解薦C++函式
- C/C++—— 寫一個函式,它的引數為指向函式的指標,返回型別也為指向函式的指標C++函式指標型別
- 指標函式 和 函式指標指標函式
- C++ 成員資料指標成員函式指標簡單測試C++指標函式
- 淺談C++指標直接呼叫類成員函式C++指標函式
- C++ 返回函式指標的函式C++函式指標
- C語言 函式指標C語言函式指標
- C++中的指標與引用詳細解讀C++指標
- C語言函式傳遞指標引數的問題詳解C語言函式指標
- C++拷貝建構函式詳解C++函式
- C++ 拷貝建構函式詳解C++函式
- C++ this 指標C++指標
- C++ 指標C++指標
- C/C++中函式指標的含義C++函式指標
- 回撥函式(c和指標)函式指標