函数指针、指针函数以及回调函数

 

函数指针和指针函数

函数指针:

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++》林锐 韩永泉 著

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章