C语言函数的回调函数

来源:嵌入式客栈
1 什么是回调函数?首先什么是“回调”呢?
我的理解是:把一段可执行的代码像参数传递那样传给其他代码,而这段代码会在某个时刻被调用执行,这就叫做回调。
如果代码立即被执行就称为同步回调,如果过后再执行,则称之为异步回调。
回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。
回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
2 为什么要用回调函数?因为可以把调用者与被调用者分开,所以调用者不关心谁是被调用者。它只需知道存在一个具有特定原型和限制条件的被调用函数。
简而言之,回调函数就是允许用户把需要调用的方法的指针作为参数传递给一个函数,以便该函数在处理相似事件的时候可以灵活的使用不同的方法。
int callback() ///《 回调函数{ // todo return 0;}int main() ///《 主函数{ // todo library(callback); ///《 库函数通过函数指针进行回调 // todo return 0;}
回调似乎只是函数间的调用,和普通函数调用没啥区别。
但仔细看,可以发现两者之间的一个关键的不同:在回调中,主程序把回调函数像参数一样传入库函数。
这样一来,只要我们改变传进库函数的参数,就可以实现不同的功能,这样有没有觉得很灵活?并且当库函数很复杂或者不可见的时候利用回调函数就显得十分优秀。
3 怎么使用回调函数?int callback_1(int a) ///《 回调函数1{ printf(“hello, this is callback_1: a = %d ”, a); return 0;}int callback_2(int b) ///《 回调函数2{ printf(“hello, this is callback_2: b = %d ”, b); return 0;}int callback_3(int c) ///《 回调函数3{ printf(“hello, this is callback_3: c = %d ”, c); return 0;}int handle(int x, int (*callback)(int)) ///《 注意这里用到的函数指针定义{ callback(x);}int main(){ handle(4, callback_1); handle(5, callback_2); handle(6, callback_3); return 0;}
如上述代码:可以看到,handle()函数里面的参数是一个指针,在main()函数里调用handle()函数的时候,给它传入了函数callback_1()/callback_2()/callback_3()的函数名,这时候的函数名就是对应函数的指针,也就是说,回调函数其实就是函数指针的一种用法。
4 回调函数实例(很有用)一个gprs模块联网的小项目,使用过的同学大概知道2g、4g、nb等模块要想实现无线联网功能都需要经历模块上电初始化、注册网络、查询网络信息质量、连接服务器等步骤,这里的的例子就是,利用一个状态机函数(根据不同状态依次调用不同实现方法的函数),通过回调函数的方式依次调用不同的函数,实现模块联网功能,如下:
/********* 工作状态处理 *********/typedef struct{ uint8_t mstatus; uint8_t (* funtion)(void); //函数指针的形式} m26_workstatus_typedef; //m26的工作状态集合调用函数/************************************************ 》m26工作状态集合函数***********************************************/m26_workstatus_typedef m26_workstatus_tab[] ={ {gprs_network_close, m26_pwrkey_off }, //模块关机 {gprs_network_open, m26_pwrkey_on }, //模块开机 {gprs_network_start, m26_work_init }, //管脚初始化 {gprs_network_conf, m26_net_config }, /at指令配置 {gprs_network_link_ctc, m26_link_ctc }, //连接调度中心 {gprs_network_wait_ctc, m26_wait_ctc }, //等待调度中心回复 {gprs_network_link_fem, m26_link_fem }, //连接前置机 {gprs_network_wait_fem, m26_wait_fem }, //等待前置机回复 {gprs_network_comm, m26_comm }, //正常工作 {gprs_network_wait_sig, m26_wait_sig }, //等待信号回复 {gprs_network_getsignal, m26_getsignal }, //获取信号值 {gprs_network_restart, m26_reset }, //模块重启}/************************************************ 》m26模块工作状态机,依次调用里面的12个函数 ***********************************************/uint8_t m26_workstatus_call(uint8_t start){ uint8_t i = 0; for(i = 0; i 《 12; i++) { if(start == m26_workstatus_tab[i].mstatus) { return m26_workstatus_tab[i].funtion(); } } return 0;}
所以,如果有人想做个nb模块联网项目,可以copy上面的框架,只需要修改回调函数内部的具体实现,或者增加、减少回调函数,就可以很简洁快速的实现模块联网。

苹果Homekit来了,您准备好了吗?
iphone8什么时候上市?iphone8概念图流出:后双摄光学变焦+卡尔察司,颜值升级堪称新一代怪兽
XREAL与宝马集团展示智能AR辅助的未来驾驶体验
如何构建一个低成本的Arduino MiniCNC绘图仪
动态补偿装置的元件构成与注意事项有哪些?
C语言函数的回调函数
PLC逻辑梯形图编程的特点
中国联通面向交通重磅发布了5G+车联网与智慧交通系列产品
Vishay推出耐高温的新款超薄、大电流电感器
表面声波触摸屏优缺点_表面声波触摸屏应用
分析解读我国智慧城市和新基建的现状
固德威逆变器+固德威电池的应用优势
SK海力士第四季转亏为盈 HBM3营收增长5倍
增强现实可以帮助学童为未来做好准备 提高儿童的积极性和创造力
无源电子分频器和有源电子分频器的区别
AM-Flow已筹集400万美元用于3D打印自动化研究
因页面太丑被吐槽,Linux Mint 官网决定重新设计
工业4.0时代物联网企业有什么新思维
挪亚检测认证再获高新技术企业认定,创新引领可持续发展
5G物联网的乌托邦