回调函数原来这么容易理解

举报
C语言与CPP编程 发表于 2021/06/03 23:23:34 2021/06/03
【摘要】 程序员相关的海量资料,点击免费获取 1 什么是回调函数? 首先什么是“回调”呢? 我的理解是:把一段可执行的代码像参数传递那样传给其他代码,而这段代码会在某个时刻被调用执行,这就叫做回调。 如果代码立即被执行就称为同步回调,如果过后再执行,则称之为异步回调。 回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数...

首先什么是“回调”呢?

我的理解是:把一段可执行的代码像参数传递那样传给其他代码,而这段代码会在某个时刻被调用执行,这就叫做回调

如果代码立即被执行就称为同步回调,如果过后再执行,则称之为异步回调

回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。

回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

2 为什么要用回调函数?

因为可以把调用者与被调用者分开,所以调用者不关心谁是被调用者。它只需知道存在一个具有特定原型和限制条件的被调用函数。

简而言之,回调函数就是允许用户把需要调用的方法的指针作为参数传递给一个函数,以便该函数在处理相似事件的时候可以灵活的使用不同的方法。

 


  
  1. int Callback()    ///< 回调函数
  2. {
  3.     // TODO
  4.     return 0;
  5. }
  6. int main()     ///<  主函数
  7. {
  8.     // TODO
  9.     Library(Callback);  ///< 库函数通过函数指针进行回调
  10.     // TODO
  11.     return 0;
  12. }

回调似乎只是函数间的调用,和普通函数调用没啥区别。

但仔细看,可以发现两者之间的一个关键的不同:在回调中,主程序把回调函数像参数一样传入库函数。

这样一来,只要我们改变传进库函数的参数,就可以实现不同的功能,这样有没有觉得很灵活?并且当库函数很复杂或者不可见的时候利用回调函数就显得十分优秀。

3 怎么使用回调函数?


  
  1. int Callback_1(int a)   ///< 回调函数1
  2. {
  3.     printf("Hello, this is Callback_1: a = %d ", a);
  4.     return 0;
  5. }
  6. int Callback_2(int b)  ///< 回调函数2
  7. {
  8.     printf("Hello, this is Callback_2: b = %d ", b);
  9.     return 0;
  10. }
  11. int Callback_3(int c)   ///< 回调函数3
  12. {
  13.     printf("Hello, this is Callback_3: c = %d ", c);
  14.     return 0;
  15. }
  16. int Handle(int x, int (*Callback)(int)) ///< 注意这里用到的函数指针定义
  17. {
  18.     Callback(x);
  19. }
  20. int main()
  21. {
  22.     Handle(4, Callback_1);
  23.     Handle(5, Callback_2);
  24.     Handle(6, Callback_3);
  25.     return 0;
  26. }

如上述代码:可以看到,Handle()函数里面的参数是一个指针,在main()函数里调用Handle()函数的时候,给它传入了函数Callback_1()/Callback_2()/Callback_3()的函数名,这时候的函数名就是对应函数的指针,也就是说,回调函数其实就是函数指针的一种用法。

4 回调函数实例(很有用)

一个GPRS模块联网的小项目,使用过的同学大概知道2G、4G、NB等模块要想实现无线联网功能都需要经历模块上电初始化、注册网络、查询网络信息质量、连接服务器等步骤,这里的的例子就是,利用一个状态机函数(根据不同状态依次调用不同实现方法的函数),通过回调函数的方式依次调用不同的函数,实现模块联网功能,如下:


  
  1. /*********  工作状态处理  *********/
  2. typedef struct
  3. {
  4.  uint8_t mStatus;
  5.  uint8_t (* Funtion)(void); //函数指针的形式
  6. } M26_WorkStatus_TypeDef;  //M26的工作状态集合调用函数
  7. /**********************************************
  8. ** >M26工作状态集合函数
  9. ***********************************************/
  10. M26_WorkStatus_TypeDef M26_WorkStatus_Tab[] =
  11. {    
  12.     {GPRS_NETWORK_CLOSE,  M26_PWRKEY_Off  }, //模块关机
  13.     {GPRS_NETWORK_OPEN,  M26_PWRKEY_On  }, //模块开机
  14.     {GPRS_NETWORK_Start,   M26_Work_Init  }, //管脚初始化
  15.     {GPRS_NETWORK_CONF,  M26_NET_Config  }, /AT指令配置
  16.     {GPRS_NETWORK_LINK_CTC,  M26_LINK_CTC  }, //连接调度中心  
  17.     {GPRS_NETWORK_WAIT_CTC, M26_WAIT_CTC  },  //等待调度中心回复 
  18.     {GPRS_NETWORK_LINK_FEM, M26_LINK_FEM  }, //连接前置机
  19.     {GPRS_NETWORK_WAIT_FEM, M26_WAIT_FEM  }, //等待前置机回复
  20.     {GPRS_NETWORK_COMM,  M26_COMM   }, //正常工作    
  21.     {GPRS_NETWORK_WAIT_Sig,  M26_WAIT_Sig  },  //等待信号回复
  22.     {GPRS_NETWORK_GetSignal,  M26_GetSignal  }, //获取信号值
  23.     {GPRS_NETWORK_RESTART,  M26_RESET   }, //模块重启
  24. }/**********************************************
  25. ** >M26模块工作状态机,依次调用里面的12个函数   
  26. ***********************************************/
  27. uint8_t M26_WorkStatus_Call(uint8_t Start)
  28. {
  29.     uint8_t i = 0;
  30.     for(i = 0; i < 12; i++)
  31.     {
  32.         if(Start == M26_WorkStatus_Tab[i].mStatus)
  33.         {          
  34.       return M26_WorkStatus_Tab[i].Funtion();
  35.         }
  36.     }
  37.     return 0;
  38. }

所以,如果有人想做个NB模块联网项目,可以copy上面的框架,只需要修改回调函数内部的具体实现,或者增加、减少回调函数,就可以很简洁快速的实现模块联网。

最近发现的一个宝藏资源分享给大家,点击领取

文章来源: blog.csdn.net,作者:C语言与CPP编程,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/weixin_41055260/article/details/116151880

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。