|
本帖最后由 inthsunshine 于 2024-7-29 11:27 编辑
前阵子看一个解码器的资料,输入数据是以回调函数形式实现,之前也一直没留意没用过,得赶紧补缺补漏
自己写了简单的测试程序运行,更好理解它们
首先是函数指针的定义,和函数定义有点象
uint8_t (*func_pt)(uint8_t a); //形参的参数名不写也可以编译通过,比如去掉a, (uint8_t)
另一种定义方法
typedef uint8_t (*func_pt1)(uint8_t);
func_pt1 func_pt;
所谓的函数指针,本质上就是一个指针变量,指向函数的变量, 和普通的指针变量类似
翻看编译后的map表,在内存占用4字节, 存储的是地址
为了使用函数指针,先定义2个简单函数,这2个函数的返回值和参数和前面的函数指针是完全一样
uint8_t callback1(uint8_t a) { return (a+1); }
uint8_t callback2(uint8_t a) { return (a-1); }
既然是函数指针,自然可以使用它,比如
uint8_t tmp;
func_pt=&callback1; //给指针赋值
tmp=(*func_pt)(6); //调用callback1,也可写成func_pt(6)
func_pt=callback2; //也可以把取地址符号&去掉,同数组名类似,函数名也代表起始地址
tmp=(*func_pt)(6); //调用callback2
当然也可以定义函数指针数组
uint8_t (*callbackfunc[]) (uint8_t)={callback1,callback2};
再调用
func_pt=callbackfunc[1];
tmp=(*func_pt)(6); //调用callback2
关键来了,函数可以成为另一个函数的入口参数,也就是函数可以当成参数传递。
比如以下函数,第2个参数是函数指针
uint8_t b(uint8_t c, uint8_t (*func)(uint8_t)) //或者uint8_t b(uint8_t c, func_pt1 func)
{ ....
return (*func)(c); }
调用该函数
tmp=b(6,callback1); //调用callback1
tmp=b(6,callback2); //调用callback2
调用b函数时,需要提供另一个函数名作为参数,然后b运行后,会执行传递过来的函数,比如callback1,callback2,那么这2个函数称为回调函数
从编译后的汇编程序看,调用b函数时,第一个参数传给内部寄存器r0, 第二个参数传给r1,也就是callback1的地址
在b函数内部,传递过来的r1,最后成了跳转指令的目标地址,实现执行回调函数callback1
使用回调函数的好处是,假设b函数里面有一些是每次都要执行的固定操作,有些是根据情况执行可变的操作,那么,可以保持不修改b程序的情况下,通过传递不同的函数,来实现可变操作,这样的b函数通常是底层函数,可以和应用程序做分离。
不过话说回来,一个人就可完成的不大的diy程序,用到回调函数的必要性不大,或者说可以用if语句也能实现类似的功能,大概比较规范的代码,或者多人协作的大程序才需要吧。
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
x
打赏
-
查看全部打赏
|