参考链接:https://www.runoob.com/w3cnote/c-callback-function.html
参考链接:http://c.biancheng.net/view/228.html
回调函数
说一下我对回调函数的理解,回调函数的意思就是,把一个函数当成另一个函数的参数。
int a( 函数类型 b ){
b();
}
用伪代码表示就是将函数b当作参数传送给a,然后在a的函数体里面执行b函数,在实际上用c语言写代码的时候会有一个问题,那就是如何将函数变成参数呢?那就要用到函数指针了,其实包括我在内,我觉得很多初学者刚开始也都不清楚啥是“函数指针”,也都没见过函数指针的定义方式。我在上一篇博客里转载了关于函数指针的一篇文章,我感觉讲的很好,用我自己的理解方式,就是说,定义了一个函数的首地址变量,这个变量里存放的就是函数体的首地址,
函数指针的定义方式如下:
int (*p)(int,int);
第一个int是函数的返回值,最后一个括号里的两个int是函数的参数,那么p就是一个函数指针了,里面存放的就是函数的首地址,其实我也思考过反正都是定义指针,为什么不能用int *p的方式定义呢?只要把p指向那个函数的首地址不就行了?如果不能用int *类型,那就用long long*类型,只不过是地址所占用的字节数不同而已,哈哈,我也不清楚为啥不能“简单粗暴”地把一个普通指针当作函数指针,这可能是c语言编译机制的问题,有哪儿位大佬造诣颇深希望能够在评论区指点迷津,
我们知道了函数指针的定义方式,其实就已经解决了怎么把函数当作参数的问题,来看下一段代码
无参数回调函数
#include<iostream>
using namespace std;
int a( void (*p)(void) ){
p();
}
void b(){
cout<<"I am b!"<<endl;
}
void c(){
cout<<"I am c!"<<endl;
}
int main(){
a(b);
a(c);
return 0;
}
执行结果:
I am b!
I am c!
我们定义了一个回调函数a,里面的参数是一个返回值为void,参数为void的函数,同时又定义了两个返回值为void,参数为void的函数a和b,并在main函数里面分别将函数b和函数c当作参数传给回调函数a
由执行结果可知,函数b和c确实执行了!但是很多时候我们的函数都是待有参数的,怎么将函数和函数的参数一块儿传给回调函数呢?,我们来看下面的代码。
有参回调函数
#include<iostream>
using namespace std;
int a(int p1,int p2, int (*p)(int,int) ){//p1和p2分别是函数指针p所代表的函数的参数
p(p1,p2);
}
int inc(int p1,int p2){
return p1+p2;
}
int sub(int p1,int p2){
return p1-p2;
}
int main(){
cout<<"b :"<<a(1,2,inc)<<endl;
cout<<"c :"<<a(1,2,sub)<<endl;
return 0;
}
执行结果:
b :3
c :-1
以上就是有参函数通过回调函数执行的格式,回调函数如果要执行有参数的函数,那么在声明回调函数的时候,不仅仅要声明有参函数的函数指针,还要声明有参函数的参数的类型,在使用回调函数的时候,将函数指针和参数,一起传给回调函数,
回调函数的函数指针
既然函数指针是用来指向函数的,那么函数指针就能够指向回调函数,下面我们展示一下通过回调函数的指针执行回调函数的例子(这部分内容应该用的不多,这是我在写操作系统的时候用到的)
void (*eip)(int,void (*x)(int));
void put(int p,void (*x)(int)){
x(p);
}
void slove(int a){
cout<<a<<endl;
}
int main(){
eip=put;
(*eip)(100,slove);
}
首先声明一个函数指针eip,这个函数指针使用来指向回调函数的,这个回调函数的返回值为void,参数分别为void (*x)(int),int,这样我们就声明了一个指向回调函数的函数指针,使用这个函数指针的方式也非常简单,首先为其赋值,在上面的代码中,我们定义了一个名为put的回调函数,在main函数钟将put赋值给eip,这样eip实际上就指向了put函数的首地址,最后再通过(*eip)(100,slove);(其实就是put(100,slove)),执行回调函数put,在回调函数put中执行函数x,x的参数为p,(其实就是执行slove(100)),自此,通过回调函数的函数指针的方式执行回调函数就这样完成了。
总结
回调函数有什么优势呢?其实一般而言,我们在写程序的时候用到的并不是很多,但是在一些场合它用起来是真的方便,它更像一个接口,相同函数类型的函数通过这个接口便能够得到执行,弊端就是通过回调函数执行的函数必须具有相同的返回值以及相同的参数类型和参数个数,这就限制了回调函数的使用范围,而在操作系统的线程切换中,并不需要参数的传递,线程(进程)与线程(进程)之间的通信并不是通过函数参数进行的,而且线程(进程)切换一去不回,因此就可以声明一种void a(void (*p)(void))的回调函数,每次切换线程的时候只需要将即将上处理器的线程函数传给回调函数就行了,这就非常方便,回调函数只有一个,只要传递不同的线程函数就能执行不同的线程,(扯远了,今天是2021年4月1日,我正在写操纵系统,参考书上遇到了从未见过的函数声明方式(就是回调函数),于是花了三个小时搞了搞回调函数,最后写下这篇博客纪念)
按照回调函数的声明结构,其实我们还可以将回调函数当作参数传递给回调函数,这样就可以实现套娃操作!下面我们来实现回调函数调用回调函数调用回调函数调用回调函数~~~~~~~~~~~~~~~~~~~~~