在C語言中
函數本身不是變量
但可以定義指向函數的指針
這種指針可以被賦值
存放於數組之中
傳遞給函數及作為函數的返回值等
--《The C Programming Language Second Edition》
下面給出幾個簡單的例子來說明指向函數的指針
第一個例子說明指向函數的指針如何說明
賦值
調用
#include
#define TESTDATE
int func(int a) /* func用於打印一個整數 */
{
return printf(%d\na);
}
main()
{
int (*FunctionPionter)(int a);
FunctionPionter = func;
(*FunctionPionter)(TESTDATE);
return ;
}
其中重點語句的含義如下
int (*FunctionPionter)(int a);
FunctionPionter: 指向一個返回整數的函數的指針這個指針有一個整數參數
FunctionPionter = func;
將FunctionPionter指向函數func其中函數必須已經定義且函數和函數指針的說明的返回值必須一致
(*FunctionPionter)(TESTDATE);
通過函數指針調用函數因為函數指針已經指向函數所以用*取出函數指針的內容就為函數本身
下面這個例子顯示如何將指向函數的指針傳遞給函數作為函數的返回類型在這個例子中有三個函數
hello返回字符指針的函數用來返回字符串hello world!\n
RetFunc返回一個指向函數的指針的函數且返回指針所指的那個函數為一個返回字符指針的函數
call返回一個void *型的指針且call有一個指向函數的指針的參數且這個函數指針返回一個字符指針
#include
#define MAX
main()
{
void *call(char *(*)());
char *(*RtnFunc())();
/* 上面兩個說明有些復雜 */
printf(%scall(RtnFunc()));
return ;
}
char *hello()
{
return Hello World!\n;
}
char *(*RtnFunc())()
{
return hello;
}
void *call(char *(*func)())
{
return (*func)();
}
上面的例子中main()無法直接調用hello函數利用兩個函數分別返回hello和調用hello實現了在main()中調用hello雖然似乎這個程序顯得多余但卻很好的說明了如何把指向函數的指針傳遞給函數作為函數的返回其中call函數利用了void *型指針的靈活機制使得call的適用性大為增加這也正是指向函數的指針的優點之一同樣的例子是《The C Programming Language Second Edition》中下面這個函數調用
qsort((void **) lineptr nlines (int (*)(void * void *))(numeric ? numcmp : strcmp));
其中使用了兩次強制類型轉換其中第二甚至是利用指向函數的指針將函數的類型進行了轉換當然上面語句在某些編譯器上無法通過因為某些編譯器要求條件表達
表達式 ? 表達式 : 表達式
中表達式2與表達式3的類型相同當然這樣的要求是不符合ANSI標准的在ANSI標准中如果表達式2與表達式3的類型不同則結果的類型由類型轉換規則決定當然我們可以變同一下先將兩個函數的類型進行強制轉換來達到目的
qsort((void **) lineptr nlines numeric ? (int (*)(void * void *))numcmp : (int (*)(void * void *))strcmp));
對於如何直接說明一個像RtnFunc一樣返回指向函數的指針的函數我查閱了不少資料都沒有找到答案最後是自己硬著頭皮摸索出來的由此我也對C的復雜說明有了更深刻的體會將在以後的技術日記中寫出來當然在我看來過多的不合適的使用這些復雜說明並不是一種好的編程風格因為它將使程序變得難以理解同時也增加了出錯的可能性
一個比較好的折衷的方法是使用typedef來使程序的含義明朗下面給出用typedef給寫上面那個程序的例子其中定義個一個類型PtoFun用typedef說明PtoFun是指向函數的指針類型指針所指的函數返回一個字符指針且沒有參數
#include
#define MAX
typedef char *(*PtoFun)();
main()
{
void *call(PtoFun);
PtoFun RtnFunc();
printf(%scall(RtnFunc()));
return ;
}
char *hello()
{
return Hello World!\n;
}
PtoFun RtnFunc()
{
return hello;
}
void *call(PtoFun func)
{
return (*func)();
}
改寫後的程序的可讀性大為增加給人一目了然的感覺
From:http://tw.wingwit.com/Article/program/net/201311/11889.html