http://blog./uid-13701930-id-336469.html 2007 第一個(gè)例子說明指向函數(shù)的指針如何說明、賦值、調(diào)用。
#include #define TESTDATE 100 int func(int a) /* func用于打印一個(gè)整數(shù) */ { return printf("%d\n",a); } main() { int (*FunctionPionter)(int a); FunctionPionter = func; (*FunctionPionter)(TESTDATE); return 0; } 其中重點(diǎn)語句的含義如下: int (*FunctionPionter)(int a); FunctionPionter: 指向一個(gè)返回整數(shù)的函數(shù)的指針,這個(gè)指針有一個(gè)整數(shù)參數(shù)。 FunctionPionter = func; 將FunctionPionter指向函數(shù)func;其中函數(shù)必須已經(jīng)定義,且函數(shù)和函數(shù)指針的說明的返回值必須一致。 (*FunctionPionter)(TESTDATE); 通過函數(shù)指針調(diào)用函數(shù);因?yàn)楹瘮?shù)指針已經(jīng)指向函數(shù),所以用*取出函數(shù)指針的內(nèi)容就為函數(shù)本身。 下面這個(gè)例子顯示如何將指向函數(shù)的指針傳遞給函數(shù)、作為函數(shù)的返回類型。在這個(gè)例子中,有三個(gè)函數(shù): hello:返回字符指針的函數(shù),用來返回字符串“hello world!\n” RetFunc:返回一個(gè)指向函數(shù)的指針的函數(shù),且返回指針?biāo)傅哪莻€(gè)函數(shù)為一個(gè)返回字符指針的函數(shù)。 call:返回一個(gè)void *型的指針,且call有一個(gè)指向函數(shù)的指針的參數(shù),且這個(gè)函數(shù)指針返回一個(gè)字符指針 #include #define MAX 100 main() { void *call(char *(*)()); char *(*RtnFunc())(); /* 上面兩個(gè)說明有些復(fù)雜 */ printf("%s",call(RtnFunc())); return 0; } char *hello() { return "Hello World!\n"; } char *(*RtnFunc())() { return hello; } void *call(char *(*func)()) { return (*func)(); } 上面的例子中,main()無法直接調(diào)用hello函數(shù),利用兩個(gè)函數(shù)分別返回hello和調(diào)用hello,實(shí)現(xiàn)了在main()中調(diào)用hello。雖然,似乎這個(gè)程序顯得多余但卻很好的說明了如何把指向函數(shù)的指針傳遞給函數(shù)、作為函數(shù)的返回。其中call函數(shù)利用了void *型指針的靈活機(jī)制,使得call的適用性大為增加,這也正是指向函數(shù)的指針的優(yōu)點(diǎn)之一。同樣的例子是《The C Programming Language Second Edition》中下面這個(gè)函數(shù)調(diào)用: qsort((void **) lineptr, 0, nlines-1, (int (*)(void *, void *))(numeric ? numcmp : strcmp)); 其中,使用了兩次強(qiáng)制類型轉(zhuǎn)換,其中第二甚至是利用指向函數(shù)的指針,將函數(shù)的類型進(jìn)行了轉(zhuǎn)換。當(dāng)然上面語句在某些編譯器上無法通過,因?yàn)槟承┚幾g器要求條件表達(dá): 表達(dá)式1 ? 表達(dá)式2 : 表達(dá)式3 中表達(dá)式2與表達(dá)式3的類型相同。當(dāng)然這樣的要求是不符合ANSI標(biāo)準(zhǔn)的。在ANSI標(biāo)準(zhǔn)中,如果表達(dá)式2與表達(dá)式3的類型不同,則結(jié)果的類型由類型轉(zhuǎn)換規(guī)則決定。當(dāng)然,我們可以變同一下,先將兩個(gè)函數(shù)的類型進(jìn)行強(qiáng)制轉(zhuǎn)換來達(dá)到目的: qsort((void **) lineptr, 0, nlines-1, numeric ? (int (*)(void *, void *))numcmp : (int (*)(void *, void *))strcmp)); 對(duì)于如何直接說明一個(gè)像RtnFunc一樣返回指向函數(shù)的指針的函數(shù),我查閱了不少資料,都沒有找到答案,最后是自己硬著頭皮摸索出來的。由此,我也對(duì)C的復(fù)雜說明有了更深刻的體會(huì),將在以后的技術(shù)日記中寫出來。當(dāng)然在我看來,過多的、不合適的使用這些復(fù)雜說明,并不是一種好的編程風(fēng)格,因?yàn)樗鼘⑹钩绦蜃兊秒y以理解,同時(shí)也增加了出錯(cuò)的可能性。 一個(gè)比較好的折衷的方法是使用typedef來使程序的含義明朗。下面給出用typedef給寫上面那個(gè)程序的例子,其中定義個(gè)一個(gè)類型PtoFun,用typedef說明PtoFun是指向函數(shù)的指針類型,指針?biāo)傅暮瘮?shù)返回一個(gè)字符指針,且沒有參數(shù)。 #include #define MAX 100 typedef char *(*PtoFun)(); main() { void *call(PtoFun); PtoFun RtnFunc(); printf("%s",call(RtnFunc())); return 0; } char *hello() { return "Hello World!\n"; } PtoFun RtnFunc() { return hello; } void *call(PtoFun func) { return (*func)(); } 改寫后的程序的可讀性大為增加,給人一目了然的感覺。 ===========================================================================
再看一個(gè)例子:
看下面的有關(guān)函數(shù)指針的賦值語句:
transition->method = (void (*)(void *, void *)) &ict_snd_invite; transition->method = (void (*)(void *, void *)) ict_snd_invite; 其中的transition變量是transition_t *類型的, typedef struct _transition_t { state_t state; type_t type; void (*method) (void *, void *); }transition_t; ict_snd_invite()函數(shù)的定義為: void ict_snd_invite (transaction_t * ict, sipevent_t * evt); 這兩條賦值語句有什么區(qū)別嗎? transition->method = (void (*)(void *, void *)) &ict_snd_invite; transition->method = (void (*)(void *, void *)) ict_snd_invite; 答案是沒有區(qū)別。
如果func是一個(gè)函數(shù),那么&func還是它自己,array也一樣。
函數(shù)名字和數(shù)組名字是常量,再取地址本來沒有意義。但編譯為了迎合什么(?),所以就允許取地址,取了也白取,還是自己。 引用函數(shù)名就是隱式引用函數(shù)地址,所以加&和不加是一樣的。 |
|