函数指针和回调函数
函数指针
函数指针是指向函数调用地址的指针。它和函数名究竟有什么关系呢?且看下文。
看一小程序
首先,先请看下边程序:
1 #include <iostream> 2 #include <string> 3 using namespace std; 4 5 void func(string s) 6 { 7 cout << s << endl; 8 } 9 10 void (*pFunc)(string s); // 不能够写成 void *pFunc(string s); 11 // 继续看下文解释 12 13 int main() 14 { 15 cout << endl; 16 func("Original Function : 1st circumstance!"); 17 (*func)("Original Function : 2nd circumstance!"); 18 19 cout << endl; 20 pFunc = &func; 21 (*pFunc)("Function pointer : 1st circumstance!"); 22 pFunc("Function pointer : 2nd circumstance!"); 23 24 cout << endl; 25 pFunc = func; 26 (*pFunc)("Function pointer : 3rd circumstance!"); 27 pFunc("Function pointer : 4th circumstance!"); 28 29 return 0; 30 }
程序的运行结果如下:
从上边程序,我们可以得到下边结论:
1. 函数指针和函数名本质上是一样的,都是指向函数调用地址的指针,只是函数名是常量指针,函数指针是变量。
2. 调用函数的写法func()、(*func)()均可,而我们大多数情况下都会写成前者,应该是(C/C++标准制定者)为了方便大家对函数的调用。
博文Function Pointers and Callbacks in C — An Odyssey如此说:
A pointer is a special kind of variable that holds the address of another variable. The same concept applies to function pointers, except that instead of pointing to variables, they point to functions. If you declare an array, say, int a[10];
then the array name a
will in most contexts (in an expression or passed as a function parameter) “decay” to a non-modifiable pointer to its first element (even though pointers and arrays are not equivalent while declaring/defining them, or when used as operands of the sizeof
operator). In the same way, for int func();
, func
decays to a non-modifiable pointer to a function. You can think of func
as a const
pointer for the time being.
void (*pFunc)()与void* pFunc()区别
对于前者,我们都知道pFunc是函数指针变量,函数的返回值是空(void)。
对于后者而言,情况却很不一样。pFunc是函数指针常量,函数的返回值是void指针。
typedef void (*pFunc)()是什么意思?
发现自己看不懂这个语句了!!!(*pFunc)()是void的别名?这说不通啊!
typedef的语法如下:
typedef type_declaration;
为什么自己会看不懂,是因为自己一直把type_declaration分成两个部分,后半部分是前半部分的别名。其实这是错的!!!type_declaration一直是一个整体,而不是分成两半!还得注意,typedef跟#define根本是两回事!
在下边的语句中,‘void (*pFunc)()’是完整的一个类型声明,也就意味着pFunc不再是一个函数指针变量,而是一个函数指针类型。
typedef void (*pFunc)()
下边是一个能够说明typedef的简单例子:
// simple typedef typedef unsigned long ulong; // the following two objects have the same type unsigned long l1; ulong l2; // more complicated typedef typedef int int_t, *intp_t, (&fp)(int, ulong), arr_t[10]; // the following two objects have the same type int a1[10]; arr_t a2; // common C idiom to avoid having to write "struct S" typedef struct {int a; int b;} S, *pS; // the following two objects have the same type pS ps1; S* ps2;
有了函数指针类型,以后我们就可以象变量一样声明函数指针,如下例:
1 #include <iostream> 2 using namespace std; 3 4 typedef void(*pFunc)(); 5 6 void myFunc() 7 { 8 cout << "Hello World!" << endl; 9 } 10 11 int main() 12 { 13 pFunc func; 14 func = &myFunc; 15 func(); 16 17 return 0; 18 }
回调函数
回调函数其实就是一个通过函数指针调用的函数!假如你把A函数的指针当作参数传给B函数,然后在B函数中通过A函数传进来的这个指针调用A函数,那么这就是回调机制。A函数就是回调函数,而通常情况下,A函数是系统在符合你设定条件的情况下会自动执行。
例如Linux下的多线程创建函数
#include <pthread.h> int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg); // 返回:若成功返回0,否则返回错误编号
中的 start_rtn 就是一个回调函数。
下边是一个简易的例子:
1 #include <iostream> 2 using namespace std; 3 4 typedef void (*callback)(int x); // 定义一个函数指针类型 5 6 void myFunc1(int x) // myFunc1 的声明要与callback一样 7 { 8 cout << "This is myFunc1 " << x << endl; 9 } 10 11 void myFunc2(int x) 12 { 13 cout << "This is myFunc2 " << x << endl; 14 } 15 16 void callMyFunc(callback cb, int x) // 把函数指针类型当做调用函数参数类型 17 { 18 cb(x); 19 } 20 21 int main() 22 { 23 callMyFunc(myFunc1, 1); 24 callMyFunc(myFunc2, 2); 25 26 return 0; 27 }
通过这个小程序可以看出,相对于普通函数调用来说,回调函数至少有如下优势:
把回调函数定义成一个类型并作为调用函数的参数类型,这样只要跟该回调函数类型有相同声明而有不同实现的函数都可以被调用函数调用。这样将极大扩展调用函数的功能。例如,我们可以定义N多个myFunc,而且互相之间实现各不相同,那对于callMyFunc来说就有N种功能。
关于回调函数详细可参考知乎上问答回调函数(callback)是什么?。