在很多情況下,尤其是讀別人所寫**的時候,對 c語言宣告的理解能力變得非常重要,而c語言本身的凝練簡約也使得c語言的宣告常常會令人感到非常困惑,因此,在這裡我用一篇的內容來集中闡述一下這個問題。
問題:宣告與函式
有一段程式儲存在起始位址為 0的一段記憶體上,如果我們想要呼叫這段程式,請問該如何去做?
答案答案是 (*(void (*)( ) )0)( )。看起來確實令人頭大,那好,讓我們知難而上,從兩個不同的途徑來詳細分析這個問題。
答案分析:從尾到頭
首先,最基本的函式宣告: void function (paramlist);
最基本的函式呼叫: function(paramlist);
鑑於問題中的函式沒有引數,函式呼叫可簡化為 function();
其次,根據問題描述,可以知道 0是這個函式的入口位址,也就是說,0是乙個函式的指標。使用函式指標的函式宣告形式是:void (*pfunction)(),相應的呼叫形式是: (*pfunction)(),則問題中的函式呼叫可以寫作:(*0)( )。
第三,大家知道,函式指標變數不能是乙個常數,因此上式中的 0必須要被轉化為函式指標。
我們先來研究一下,對於使用函式指標的函式:比如 void (*pfunction)( ),函式指標變數的原型是什麼?這個問題很簡單,pfunction函式指標原型是( void (*)( ) ),即去掉變數名,清晰起見,整個加上()號。
所以將 0強制轉換為乙個返回值為void,引數為空的函式指標如下:( void (*)( ) )。
ok,結合2)和3)的分析,結果出來了,那就是:(*(void (*)( ) )0)( ) 。
答案分析:從頭到尾理解答案
(void (*)( )) ,是乙個返回值為void,引數為空的函式指標原型。
(void (*)( ))0,把0轉變成乙個返回值為void,引數為空的函式指標,指標指向的位址為0.
*(void (*)( ))0,前面加上*表示整個是乙個返回值為void的函式的名字
(*(void (*)( ))0)( ),這當然就是乙個函式了。
我們可以使用 typedef清晰宣告如下:
typedef void (*pfun)( );
這樣定義之後,pfun就是乙個返回型別為void無引數的函式指標變數了。
這樣函式變為 (*(pfun)0 )( );
問題:三個宣告的分析
對宣告進行分析,最根本的方法還是模擬替換法,從那些最基本的宣告上進行模擬,簡化,從而進行理解,下面通過分析三個例子,來具體闡述如何使用這種方法。
# 1:int* (*a[5])(int, char*);
首先看到識別符號名 a,""優先順序大於"*",a與"[5]"先結合。所以a是乙個陣列,這個陣列有5個元素,每乙個元素都是乙個指標,指標指向"(int, char*)",很明顯,指向的是乙個函式,這個函式引數是"int, char*",返回值是"int*"。ok,結束了乙個。:)
# 2:void (*b[10]) (void (*)());
b是乙個陣列,這個陣列有10個元素,每乙個元素都是乙個指標,指標指向乙個函式,函式引數是"void (*)()"【注10】,返回值是"void"。完畢!
注意:這個引數又是乙個指標,指向乙個函式,函式引數為空,返回值是 "void"。
# 3. doube(*)() (*pa)[9];
pa是乙個指標,指標指向乙個陣列,這個陣列有9個元素,每乙個元素都是"doube(*)()"(也即乙個函式指標,指向乙個函式,這個函式的引數為空,返回值是"double")。
c語言中的函式指標
函式在記憶體中有乙個物理位置,而這個位置是可以賦給乙個指標的。一零點函式的位址就是該函式的入口點。因此,函式指標可被用來呼叫乙個函式。函式的位址是用不帶任何括號或引數的函式名來得到的。(這很類似於陣列位址的得到方法,即,在只有陣列名而無下標是就得到陣列位址。)
怎樣說明乙個函式指標變數呢 ?
為了說明乙個變數 fn_pointer 的型別是"返回值為 int 的函式指標", 你可以使用下面的說明語句:
int (*fn_pointer) ();
為了讓編譯器能正確地解釋這句語句, *fn_pointer 必須用括號圍起來。若漏了這對括號, 則:
int *fn_pointer ();
的意思完全不同了。fn_pointer 將是乙個函式名, 其返回值為 int 型別的指標。
函式指標變數
在c語言中規定,乙個函式總是占用一段連續的記憶體區, 而函式名就是該函式所佔記憶體區的首位址。 我們可以把函式的這個首位址 ( 或稱入口位址 ) 賦予乙個指標變數, 使該指標變數指向該函式。然後通過指標變數就可以找到並呼叫這個函式。 我們把這種指向函式的指標變數稱為 " 函式指標變數 " 。
函式指標變數定義的一般形式為:
型別說明符 (* 指標變數名 )();
其中 " 型別說明符 " 表示被指函式的返回值的型別。 "(* 指標變數名 )" 表示 "*" 後面的變數是定義的指標變數。 最後的空括號表示指標變數所指的是乙個函式。
例如: int (*pf)();
表示 pf 是乙個指向函式入口的指標變數,該函式的返回值 ( 函式值 ) 是整型。
下面通過例子來說明用指標形式實現對函式呼叫的方法。
int max(int a,int b)
main()
從上述程式可以看出用,函式指標變數形式呼叫函式的步驟如下:
1. 先定義函式指標變數,如後一程式中第 9 行 int (*pmax)(); 定義 pmax 為函式指標變數。
2. 把被調函式的入口位址 ( 函式名 ) 賦予該函式指標變數,如程式中第 11 行 pmax=max;
3. 用函式指標變數形式呼叫函式,如程式第 14 行 z=(*pmax)(x,y); 呼叫函式的一般形式為: (* 指標變數名 ) ( 實參表 ) 使用函式指標變數還應注意以下兩點:
a. 函式指標變數不能進行算術運算,這是與陣列指標變數不同的。陣列指標變數加減乙個整數可使指標移動指向後面或前面的陣列元素,而函式指標的移動是毫無意義的。
b. 函式呼叫中 "(* 指標變數名 )" 的兩邊的括號不可少,其中的 * 不應該理解為求值運算,在此處它只是一種表示符號。
C語言中的 void 0 與 void 0
前幾天看到乙個巨集,它大概是這樣的 define assert param expr expr void 0 assert failed u8 file line 的含意簡單,關鍵是那個 void 0 的用法,我還是第一次見到 我用 void 的時候,有兩種情況 1.放到函式前面,強調函式沒有返回值...
C語言中的 void 0 與 void 0
前幾天看到乙個巨集,它大概是這樣的 define assert param expr expr void 0 assert failed u8 file line 的含意簡單,關鍵是那個 void 0 的用法,我還是第一次見到 別笑 我用 void 的時候,有兩種情況 1.放到函式前面,強調函式沒有...
原始碼學習之void 0
今天看原始碼的時候看到void 0這樣的寫法,平時在業務 裡基本沒有這樣的寫法,於是學習了一下。在控制台執行了一下void 0,得到返回值是undefined。在mdn上搜了一下void,了解到 以vue的原始碼為例 var createemptyvnode function text 這段 用於建...