由于最近项目需求,需要学习一些回调函数的知识。对于指针本来掌握就不够熟练的我来说,网上的资料看的也是一头雾水。其实,看文字描述不如看代码描述。下面就介绍一下我所理解的回调函数。
介绍之前,必须提醒读者,不要被“回调”两个字所迷惑,很多人觉得回调函数神秘,就是有了先入为主的观念,被“回调”所欺骗。我们首先来看一段很简单的例子:
int main(int argc,char* argv[])
{
printf("Hello World!\n");
return 0;
}
这是文明很熟悉的“Hello World!”,如何使这个程序更高级一些呢?自然有人想到使用函数调用的方法,于是就有了下面这段改进版:
void Invoke(char* s);
int main(int argc,char* argv[])
{
Invoke("Hello World!\n");
return 0;
}
void Invoke(char* s)
{
printf(s);
}
有了函数调用程序确实变得高端了一些,但是回调函数需要我们具备一定的函数指针的技能,如果再升级一下这个程序,会是什么样子呢?
void Invoke(char* s);
int main()
{
void (*fp)(char* s); //声明一个函数指针(fp)
fp=Invoke; //将Invoke函数的入口地址赋值给fp
fp("Hello World!\n"); //函数指针fp实现函数调用
return 0;
}
void Invoke(char* s)
{
printf(s);
}
在这个程序中,我们把函数的入口地址给了一个指针,通过调用指针,来间接的调用函数。在此基础上我们来介绍回调函数。如果我们把Invoke函数的地址作为一个参数传递到一个中间函数中,然后在主函数中通过调用这个中间函数来输出这个函数,也可以实现相同的功能。虽然看起来好像绕了很长的一段路,但是这样做总是有它适用的场景,这种场景在下文中会有介绍。下面就是使用回调函数后的程序:
//定义回调函数
void PrintfText()
{
printf("Hello World!\n");
}
//定义实现回调函数的"调用函数"
void CallPrintfText(void (*callfuct)())
{
callfuct();
}
//在main函数中实现函数回调
int main(int argc,char* argv[])
{
CallPrintfText(PrintfText);
return 0;
}
很明显,我们能看到两个函数,一个是我们自己写的有一定功能的函数(PrintfText),另一个是中间函数(CallPrintfText),最后我们在主函数需要使用PrintfText的地方,通过调用CallPrintfText来实现函数的调用。
这就是一个最简单最基本的回调函数的例子。在这里并没有体现出回调函数的灵活之处,我们再举一个例子来说明。
/* para_callback.h */
#ifndef PARA_CALLBACK_H
#define PARA_CALLBACK_H
typedef void (*callback_t)(void *);
extern void repeat_three_times(callback_t, void *);
#endif
/* para_callback.c */
#include "para_callback.h"
void repeat_three_times(callback_t f, void *para)
{
f(para);
f(para);
f(para);
}
/* main.c */
#include <stdio.h>
#include "para_callback.h"
void say_hello(void *str)
{
printf("Hello %s\n", (const char *)str);
}
void count_numbers(void *num)
{
int i;
for(i=1; i<=(int)num; i++)
printf("%d ", i);
putchar('\n');
}
int main(void)
{
repeat_three_times(say_hello, "Guys");
repeat_three_times(count_numbers, (void *)4);
return 0;
}
从这个例子可以看到,调用函数不需要知道回调函数具体的功能,只要参数列表对应,就可以调用同一个中间函数,完成不同的功能。
相信,读到这里,你已经对回调函数有了一些认识,我们再把这些认识总结成文字。所以到底什么是回调函数呢?简而言之,回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用为调用它所指向的函数时,我们就说这是回调函数。
举个现实中的例子:你到一个商店买东西,刚好你要的东西没有货,于是你在店员那里留下了你的电话,过了几天店里有货了,店员就打了你的电话,然后你接到电话后就到店里去取了货。在这个例子里,你的电话号码就叫回调函数,你把电话留给店员就叫登记回调函数,店里后来有货了叫做触发了回调关联的事件,店员给你打电话叫做调用回调函数,你到店里去取货叫做响应回调事件。
应用程序,回调函数和中间函数的关系如下:
在使用回调函数时,主要有三步:1,声明;2,定义;3,设置触发条件,就是在你的函数中把你的回调函数名称转化为地址作为一个参数,以便于系统调用。回调函数就相当于一个中断处理函数,由系统在符合你设定的条件时自动调用。
所谓回调函数就是按照一定的形式由你定义并编写实现内容,当发生某种事件时,而由系统或其它函数来调用的函数。使用回调函数实际上就是在调用某个函数时,将自己编写的一个函数的地址作为参数传递给那个函数。而那个函数在需要的时候,也就是某种事情发生的时候,利用传递的函数地址调用回调函数,这时你可以利用这个机会在回调函数中处理消息或完成一定的操作。回调函数只能是全局函数,或者是静态函数,因为这个函数只是在这个类中使用,所以为了维护类的完整性,我们用类的静态成员函数来做回调函数。
这就是我所理解的回调函数,希望能够帮助到你。