转自 http://blog.csdn.net/neo_ustc/article/details/8960047
精妙比喻:回调函数就像您随身带的BP机:告诉别人号码,在它有事情时Call您
回调用于层间协作,上层将本层函数安装在下层,这个函数就是回调,而下层在一定条件下触发回调,例如作为一个驱动,是一个底层,他在收到一个数据时,除了完成本层的处理工作外,还将进行回调,将这个数据交给上层应用层来做进一步处理,这在分层的数据通信中很普遍。
其实回调和API非常接近,他们的共性都是跨层调用的函数。但区别是API是低层提供给高层的调用,一般这个函数对高层都是已知的;而回调正好相反,他是高层提供给低层的调用,对于低层他是未知的,必须由高层进行安装,这个安装函数其实就是一个低层提供的API,安装后低层不知道这个回调的名字,但它通过一个函数指针来保存这个回调,在需要调用时,只需引用这个函数指针和相关的参数指针。
其实:回调就是该函数写在高层,低层通过一个函数指针保存这个函数,在某个事件的触发下,低层通过该函数指针调用高层那个函数。回调在C语言中是通过函数指针来实现的,通过将回调函数的地址传给被调函数从而实现回调。因此,要实现回调,必须首先定义函数指针,请看下面的例子:
void Func(char *s);// 函数原型
void (*pFunc) (char *);//函数指针
可以看出,函数的定义和函数指针的定义非常类似。
一般的化,为了简化函数指针类型的变量定义,提高程序的可读性,我们需要把函数指针类型自定义一下。
typedef void(*pcb)(char *);
回调函数可以象普通函数一样被程序调用,但是只有它被当作参数传递给被调函数时才能称作回调函数。
被调函数的例子:
例一:
void GetCallBack(pcb callback)
{
/*do something*/
}
用户在调用上面的函数时,需要自己实现一个pcb类型的回调函数:
void fCallback(char *s)
{
/* do something */
}
然后,就可以直接把fCallback当作一个变量传递给GetCallBack,
GetCallBack(fCallback);
如果赋了不同的值给该参数,那么调用者将调用不同地址的函数。赋值可以发生在运行时,这样使你能实现动态绑定。
例二:
//Test.c
#include <stdlib.h>
#include <stdio.h>
int Test1()
{
int i;
for (i=0; i<30; i++)
{
printf("The %d th charactor is: %c\n", i, (char)('a' + i%26));
}
return 0;
}
int Test2(int num)
{
int i;
for (i=0; i<num; i++)
{
printf("The %d th charactor is: %c\n", i, (char)('a' + i%26));
}
return 0;
}
void Caller1(void (*ptr)()) //指向函数的指针作函数参数
{
(*ptr)();
}
void Caller2(int n, int (*ptr)()) //指向函数的指针作函数参数,这里第一个参数是为指向函数的指针服务的,
{ //不能写成void Caller2(int (*ptr)(int n)),这样的定义语法错误。
(*ptr)(n);
return;
}
int main()
{
printf("************************\n");
Caller1(Test1); //相当于调用Test2();
printf("&&&&&&************************\n");
Caller2(30, Test2); //相当于调用Test2(30);
return 0;
}
以上通过将回调函数的地址传给调用者从而实现调用,但是需要注意的是带参回调函数的用法。要实现回调,必须首先定义函数指针。函数指针的定义这里稍微提一下。比如:
int (*ptr)(); 这里ptr是一个函数指针,其中(*ptr)的括号不能省略,因为括号的优先级高于星号,那样就成了一个返回类型为整型的函数声明了