C语⾔回调函数详解(全⽹最全)
⽂章⽬录
⼀、函数指针
在讲回调函数之前,我们需要了解函数指针。
我们都知道,C语⾔的灵魂是指针,我们经常使⽤整型指针,字符串指针,结构体指针等
int*p1;
char*p2;
STRUCT *p3;//STRUCT为我们定义的结构体
但是好像我们⼀般很少使⽤函数指针,我们⼀般使⽤函数都是直接使⽤函数调⽤。
下⾯我们来了解⼀下函数指针的概念和使⽤⽅法。
1.概念
嵌入式工程师接私活网站
函数指针是指向函数的指针变量。
通常我们说的指针变量是指向⼀个整型、字符型或数组等变量,⽽函数指针是指向函数。
函数指针可以像⼀般函数⼀样,⽤于调⽤函数、传递参数。
函数指针的定义⽅式为:
函数返回值类型 (* 指针变量名) (函数参数列表);
“函数返回值类型”表⽰该指针变量可以指向具有什么返回值类型的函数;“函数参数列表”表⽰该指针变量可以指向具有什么参数列表的函数。这个参数列表中只需要写函数的参数类型即可。
我们看到,函数指针的定义就是将“函数声明”中的“函数名”改成“(*指针变量名)”。但是这⾥需要注意的是:“(*指针变量
名)”两端的括号不能省略,括号改变了运算符的优先级。如果省略了括号,就不是定义函数指针⽽是⼀个函数声明了,即声明了⼀个返回值类型为指针型的函数。
那么怎么判断⼀个指针变量是指向变量的指针变量还是指向函数的指针变量呢?⾸先看变量名前⾯有
没有“”,如果有“”说明是指针变量;其次看变量名的后⾯有没有带有形参类型的圆括号,如果有就是指向函数的指针变量,即函数指针,如果没有就是指向变量的指针变量。
最后需要注意的是,指向函数的指针变量没有 ++ 和 – 运算。
⼀般为了⽅便使⽤,我们会选择
typedef 函数返回值类型 (* 指针变量名) (函数参数列表);
⽐如
typedef int(*Fun1)(int);//声明也可写成int (*Fun1)(int x),但习惯上⼀般不这样。
typedef int(*Fun2)(int,int);//参数为两个整型,返回值为整型
typedef void(*Fun3)(void);//⽆参数和返回值
typedef void*(*Fun4)(void*);//参数和返回值都为void*指针
2,如何⽤函数指针调⽤函数
给⼤家举⼀个例⼦:
int Func(int x);/*声明⼀个函数*/
int(*p)(int x);/*定义⼀个函数指针*/
p = Func;/*将Func函数的⾸地址赋给指针变量p*/
p =&Func;/*将Func函数的⾸地址赋给指针变量p*/
赋值时函数 Func 不带括号,也不带参数。由于函数名 Func 代表函数的⾸地址,因此经过赋值以后,指针变量 p 就指向函数 Func() 代码的⾸地址了。
下⾯来写⼀个程序,看了这个程序你们就明⽩函数指针怎么使⽤了:
#include<stdio.h>
int Max(int,int);//函数声明
int main(void)
{
int(*p)(int,int);//定义⼀个函数指针
int a, b, c;
p = Max;//把函数Max赋给指针变量p, 使p指向Max函数
element是什么意思啊printf("please enter a and b:");
scanf("%d%d",&a,&b);
c =(*p)(a, b);//通过函数指针调⽤Max函数
printf("a = %d\nb = %d\nmax = %d\n", a, b, c);
return0;
}
int Max(int x,int y)//定义Max函数
{
int z;
冒泡排序代码c语言
if(x > y)
{
z = x;
}
else
{
z = y;
}
return z;
}
特别注意的是,因为函数名本⾝就可以表⽰该函数地址(指针),因此在获取函数指针时,可以直接⽤函数名,也可以取函数的地址。
p = Max可以改成 p =&Max
c =(*p)(a, b)可以改成 c =p(a, b)
3.函数指针作为某个函数的参数
既然函数指针变量是⼀个变量,当然也可以作为某个函数的参数来使⽤的。
⽰例:
limit怎么写#include<stdio.h>
#include<stdlib.h>
typedef void(*FunType)(int);
免费网站大全黄页动漫视频免费观看含蓄草//前加⼀个typedef关键字,这样就定义⼀个名为FunType函数指针类型,⽽不是⼀个FunType变量。
//形式同 typedef int* PINT;
void myFun(int x);
void hisFun(int x);
void herFun(int x);
void callFun(FunType fp,int x);
int main()
{
callFun(myFun,100);//传⼊函数指针常量,作为回调函数
callFun(hisFun,200);
callFun(herFun,300);
return0;
}
void callFun(FunType fp,int x)
{
fp(x);//通过fp的指针执⾏传递进来的函数,注意fp所指的函数有⼀个参数
}
void myFun(int x)
{
printf("myFun: %d\n",x);
}
void hisFun(int x)
{
printf("hisFun: %d\n",x);
}
void herFun(int x)
{
printf("herFun: %d\n",x);
}
输出:
4.函数指针作为函数返回类型
有了上⾯的基础,要写出返回类型为函数指针的函数应该不难了,下⾯这个例⼦就是返回类型为函数指针的函数:
void(*func5(int,int,float))(int,int)
{
...
}
在这⾥, func5 以 (int, int, float) 为参数,其返回类型为 void (\*)(int, int) 。在C语⾔中,变量或者函数的声明也是⼀个⼤学问,想要了解更多关于声明的话题,可以参考我之前的⽂章 - 。这本书的第三章花了整整⼀章的内容来讲解如何读懂C语⾔的声明。
5.函数指针数组
在开始讲解回调函数前,最后介绍⼀下函数指针数组。既然函数指针也是指针,那我们就可以⽤数组来存放函数指针。下⾯我们看⼀个函数指针数组的例⼦:
/* ⽅法1 */
void(*func_array_1[5])(int,int,float);
/* ⽅法2 */
typedef void(*p_func_array)(int,int,float);
p_func_array func_array_2[5];
上⾯两种⽅法都可以⽤来定义函数指针数组,它们定义了⼀个元素个数为5,类型是 void (\*)(int, int, float) 的函数指针数组。
6.函数指针总结
1. 函数指针常量 :Max;函数指针变量:p;
2. 数名调⽤如果都得如(*myFun)(10)这样,那书写与读起来都是不⽅便和不习惯的。所以C语⾔的设计者们才会设计成⼜可允许
myFun(10)这种形式地调⽤(这样⽅便多了,并与数学中的函数形式⼀样)。
3. 函数指针变量也可以存⼊⼀个数组内。数组的声明⽅法:int (*fArray[10]) ( int );
⼆、回调函数
1.什么是回调函数
我们先来看看百度百科是如何定义回调函数的:
回调函数就是⼀个通过函数指针调⽤的函数。如果你把函数的指针(地址)作为参数传递给另⼀个函数,当这个指针被⽤来调⽤其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现⽅直接调⽤,⽽是在特定的事件或条件发⽣时由另外的⼀⽅调⽤的,⽤于对该事件或条件进⾏响应。
这段话⽐较长,也⽐较绕⼝。下⾯我通过⼀幅图来说明什么是回调:
假设我们要使⽤⼀个排序函数来对数组进⾏排序,那么在主程序(Main program)中,我们先通过库,选择⼀个库排序函数(Library function)。但排序算法有很多,有冒泡排序,选择排序,快速排序,归并排序。同时,我们也可能需要对特殊的对象进⾏排序,⽐如特定的结构体等。库函数会根据我们的需要选择⼀种排序算法,然后调⽤实现该算法的函数来完成排序⼯作。这个被调⽤的排序函数就是回调
函数(Callback function)。
结合这幅图和上⾯对回调函数的解释,我们可以发现,要实现回调函数,最关键的⼀点就是要将函数的指针传递给⼀个函数(上图中是库函数),然后这个函数就可以通过这个指针来调⽤回调函数了。注意,回调函数并不是C语⾔特有的,⼏乎任何语⾔都有回调函数。在C语⾔中,我们通过使⽤函数指针来实现回调函数。
我的理解是:把⼀段可执⾏的代码像参数传递那样传给其他代码,⽽这段代码会在某个时刻被调⽤执⾏,这就叫做回调。
如果代码⽴即被执⾏就称为同步回调,如果过后再执⾏,则称之为异步回调。
回调函数就是⼀个通过函数指针调⽤的函数。如果你把函数的指针(地址)作为参数传递给另⼀个函数,当这个指针被⽤来调⽤其所指向的函数时,我们就说这是回调函数。
类似爱情原唱回调函数不是由该函数的实现⽅直接调⽤,⽽是在特定的事件或条件发⽣时由另外的⼀⽅调⽤的,⽤于对该事件或条件进⾏响应。
2 为什么要⽤回调函数?
因为可以把调⽤者与被调⽤者分开,所以调⽤者不关⼼谁是被调⽤者。它只需知道存在⼀个具有特定原型和限制条件的被调⽤函数。
简⽽⾔之,回调函数就是允许⽤户把需要调⽤的⽅法的指针作为参数传递给⼀个函数,以便该函数在处理相似事件的时候可以灵活的使⽤不同的⽅法。
int Callback()///< 回调函数
{
// TODO
return0;
}
int main()///< 主函数
{
// TODO
Library(Callback);///< 库函数通过函数指针进⾏回调
// TODO
return0;
}
回调似乎只是函数间的调⽤,和普通函数调⽤没啥区别。
但仔细看,可以发现两者之间的⼀个关键的不同:在回调中,主程序把回调函数像参数⼀样传⼊库函数。
这样⼀来,只要我们改变传进库函数的参数,就可以实现不同的功能,这样有没有觉得很灵活?并且当库函数很复杂或者不可见的时候利⽤回调函数就显得⼗分优秀。
3 怎么使⽤回调函数?
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论