定义和使用场合
回调函数是指 使用者自己定义一个函数,实现这个函数的程序内容,然后把这个函数(入口地址)作为参数传入别人(或系统)的函数中,由别人(或系统)的函数在运行时来调用的函数。
函数是你实现的,但由别人(或系统)的函数在运行时通过参数传递的方式调用,这就是所谓的回调函数。简单来说,就是由别人的函数运行期间来回调你实现的函数。
这一设计允许了底层代码调用在高层定义的子程序。C语言中回调函数主要通过函数指针的方式实现。
图1-1 回调函数在软件系统的调用结果
回调的用途十分广泛
结构解析
回调函数主要结构有三部分组成:主函数、调用函数和被调函数。C语言中,被调函数通常以函数指针(指向对应函数的入口地址)的形式出现。
这里给出一个最简单的回调函数结构,并解析相关数据结构。
//定义回调函数
void PrintfText()
{
printf("Hello World!\n");
}
//定义实现回调函数的"调用函数"
void CallPrintfText(void (*callfuct)())
{
callfuct();
}
//实现函数回调
int main(int argc,char* argv[])
{
CallPrintfText(PrintfText);
return 0;
}
调用函数向其函数中传递 void (*callfuct)(void) 这是一个 void callfuct(void) 函数的入口地址,即PC指针可以通过移动到该地址执行void callfuct(void) 函数,可以通过类比数组来理解。
实现函数调用中,函数调用了“调用函数”,再在其中进一步调用“被调函数”。相比于主函数直接调用“被调函数”,这种方法为使用者,而不是开发者提供了灵活的接口。另外,函数入口可以像变量一样设定同样为开发者提供了灵活性。
实例分析
这里分析一个lwip中较为复杂的回调函数使用范例:
void httpd_init(void)
{
struct tcp_pcb * pcb;
pcb = tcp_new();
tcp_bind(pcb,IP_ADDR_ANY,80);
pcb = tcp_listen(pcb);
tcp_accept(pcb, http_accept);
}
void
tcp_accept(struct tcp_pcb * pcb, err_t(* accept)(void *arg, struct tcp_pcb *newpcb, err_t err))
static err_t http_accept(void *arg, struct tcp_pcb * pcb, err_t err)
{
/* set the prio of callback function, important */
tcp_setprio(pcb, TCP_PRIO_MIN);
tcp_recv(pcb, http_recv);
return ERR_OK;
}
void
tcp_recv(struct tcp_pcb * pcb, err_t (* recv)(void * arg, struct tcp_pcb * tpcb, struct pbuf * p, err_t err))
static err_t http_recv(void *arg, struct tcp_pcb * pcb, struct pbuf *p, err_t err)
{
/* html handler by user's definition */
/* use tcp_write(pcb, message, sizeof message, 0) to send message */
}void ht
这里调用两个回调函数,模块化分离了tcp和http,感兴趣可以看看lwip的RAW部分。
相关参考
- http://partow.net/programming/templatecallback/index.html
- http://blog.csdn.net/callmeback/article/details/4242260
- http://www.cnblogs.com/chenyuming507950417/archive/2012/01/02/2310114.html