函數指針和指針函數
函數指針:
int func ( );
int (*func) ( ); //指針兩側的括號不能省略,表示先對func解引用,然後再調用相應的函數
函數指針是一個指向函數的指針, 其實就是函數, 因爲ANSI C標準將func ( )認爲是(*func)( ) 的簡寫形式 ,並且推薦使用func ( )形式,因爲它更符合函數調用的邏輯。
注:
但是我在測試的時候,定義爲int func ( );和定義爲int (*func) ( );還是有差別的,
int func ( );表示定義了一個函數
int (*func) ( );表示定義了一個指向函數的指針。
函數指針的使用:
void test ( );
int wrong_match (int);
void (*ptf) ( );
下面的初始化是錯誤的,因爲函數指針的類型與函數的類型不 匹配:
test = wrong_match;
test = & wrong_match;
ptf = wrong_match;
ptf = & wrong_match;
以下初始化及賦值是合法的:
ptf = test;
ptf = &test;
C語言規定函數名會被轉換爲指向這個函數的指針,除非這個函數名作爲 & 操作符或sizeof操作符的操作數。
( 注意:函數名用於 sizeof 的操作數是非法的 )
也就是說,在
ptf = test;
中test被自動轉換爲&test。
而在
ptf = &test;
中已經顯示使用了&test,所以test就不會再發生轉換了。
因此直接引用函數名等效於在函數名上應用 & 運算符,兩種方法都會得到指向該函數的指針。
測試例程和運行結果:
pointer_to_func.c文件:
1 #include <stdio.h>
2
3 int testfunc(void)
4 {
5 printf("%s: call me(%p)./n", __func__, testfunc);
6 return 0;
7 }
8
9 int main(int argc, char *argv[])
10 {
11 /* define a pointer to function */
12 void (*func)(void);
13 //void func(void);
14
15 func = (void *)testfunc;
16
17 printf(" testfunc(%p)/n", testfunc);
18 printf("&testfunc(%p)/n", &testfunc);
19 printf("*testfunc(0x%x)/n", *testfunc);
20
21 /* run function */
22 func();
23 (*func)();
24
25 return 0;
26 }
輸出結果:
[lhcX86@horizon tmp]$ make pointer_to_func
cc pointer_to_func.c -o pointer_to_func
[lhcX86@horizon tmp]$ ./pointer_to_func
testfunc(0x8048374)
&testfunc(0x8048374)
*testfunc(0x8048374)
testfunc: call me(0x8048374).
testfunc: call me(0x8048374).
指針函數:
指針類型的函數,返回指針的函數。注意函數的返回值不僅僅侷限於指向變量的指針,也可以是指向函數的指針。
首先來看這個聲明:
int (* function(int) ) (double*, char);
要了解此聲明的含義,首先來看function(int),將function聲明爲一個函數,它帶有一個int型的形式參數,這個函數的返回值爲一個指針,正是我們本將開頭講過的函數指針 ── int (*) (double*, char);
這個指針指向一個函數,此函數返回int型並帶有兩個分別是double*型和char型的形參。如果使用typedef可以將這個聲明簡化:
定義一個 ptf 爲這個 函數指針的類型:
typedef int (*ptf) (double*, char);
定義返回值類型爲ptf 函數指針的指針函數:
ptf function( int );
要說明一下,對於typedef int (*ptf) (double*, char);
注意:
不要用#define的思維來看待typedef,如果用#define的思維來看的話會以爲(*ptf)(double*, char)是int的別名,但這樣的別名看起來好像又不是合法的名字,於是會處於迷茫狀態。
實際上,上面的語句把ptf定義爲一種函數指針類型的別名,使得ptf和函數指針類型int (*) (double*, char);等價 。
回調函數
爲什麼要使用回調函數?
回調函數是一個程序員不能顯式調用的函數;
通過將回調函數的地址傳給 調用者從而實現調用。
在我們想通過一個統一函數接口實現不同的內容 ,這時用回掉函數非常合適。
什麼是回調函數?
簡而言之,回調函數是一個通過函數指針調用的函數。如果你把函數指針(函數的入口地址)傳遞給另一個函數,當這個函數指針被用來調用它所指向的函數時,我們就說這個函數是回調函數。
例子:
下面時一個簡單的回調函數的例子,供理解:
callback.c
1 /*
2 * callback.c
3 *
4 * 4bsfreedom(at)gmail.com
5 * */
6
7 #include <stdio.h>
8
9 int func1(void)
10 {
11 printf("I'm callback function/n");
12
13 return 0;
14 }
15
16 int func2(int x)
17 {
18 printf("func2 x is (%d)/n", x);
19
20 return 0;
21 }
22
23 int func3(int x)
24 {
25 x = 2345;
26 printf("do different thing in func3 (%d)/n", x);
27
28 return 0;
29 }
30
31 void callback_test( int(*func)() )
32 {
33
34 /* callback function here */
35 (*func)();
36 }
37
38 void callback_api( int(*func)(), int bb)
39 {
40
41 /* callback function here */
42 (*func)(bb);
43 }
44
45 int main(int argc, char * argv[])
46 {
47 //printf("%d/n", argc);
48 callback_test(func1);
49 callback_api(func2, argc);
50 callback_api(func3, argc);
51
52 return 0;
53 }
運行結果:
[lhcX86@horizon tmp]$ make callback
cc callback.c -o callback
[lhcX86@horizon tmp]$ ./callback
I'm callback function
func2 x is (1)
do different thing in func3 (2345)
References:
《探討C語言中的回調函數》
http://www.blogjava.net/huyi2006/articles/180169.html
《異步消息的傳遞-回調機制》
http://www.ibm.com/developerworks/cn/linux/l-callback/index.html
《分清函數指針和指針函數》
http://blog.csdn.net/porscheyin/archive/2008/12/06/3461632.aspx
PS:
爲了加深自己的理解,和一些其它的C語言基本功,我最近查看了三本經典書籍來補充C語言知識,書名這裏與大家共享一下。
《C Traps and Pitfalls》(C陷阱與缺陷) Andrew Koenig 著
《The C Programming Language》(C程序設計) Dennis M.Ritchie 著
《高質量程序設計指南──C/C++》林銳 韓永泉 著