0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

C语言函数的回调函数

工程师 来源:嵌入式客栈 作者:嵌入式客栈 2020-09-11 09:57 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

来源:嵌入式客栈

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上面的框架,只需要修改回调函数内部的具体实现,或者增加、减少回调函数,就可以很简洁快速的实现模块联网。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • C语言
    +关注

    关注

    183

    文章

    7642

    浏览量

    144556
  • 函数
    +关注

    关注

    3

    文章

    4406

    浏览量

    66812
收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    LUA例程-常用的函数使用说明

    详细说明LUA脚本函数功能和对应的应用实例。对于LUA脚本编程有很大的帮助和提高技能。
    发表于 11-24 16:43 0次下载

    大彩讲堂:VisualHMI-LUA教程-on_screen_change函数使用指南

    on_screen_change函数使用指南
    的头像 发表于 08-31 16:32 564次阅读
    大彩讲堂:VisualHMI-LUA教程-on_screen_change<b class='flag-5'>回</b><b class='flag-5'>调</b><b class='flag-5'>函数</b>使用指南

    大彩讲堂:VisualHMI-LUA教程-on_update函数使用指南

    函数使用指南
    的头像 发表于 08-31 16:25 610次阅读
    大彩讲堂:VisualHMI-LUA教程-on_update<b class='flag-5'>回</b><b class='flag-5'>调</b><b class='flag-5'>函数</b>使用指南

    详解hal_entry入口函数

    当使用RTOS时,程序从main函数开始进行线程调度;当没有使用RTOS时,C语言程序的入口函数main函数调用了hal_entry
    的头像 发表于 07-25 15:34 1653次阅读

    C语言中的内联函数与宏

    C编程中,内联函数和宏都用于避免函数调用的开销并编写可复用的逻辑部分,但它们在工作方式和安全性方面存在显著差异。
    的头像 发表于 07-25 15:10 1706次阅读
    <b class='flag-5'>C</b><b class='flag-5'>语言</b>中的内联<b class='flag-5'>函数</b>与宏

    大彩讲堂:VisualHMI-LUA教程-on_press函数使用指南

    一、适合范围本文档适用于VisualHMI平台,Lua脚本语言为V5.3版本,配合工程可以完成大部分的内部逻辑处理。二、概述on_press(state,x,y)触摸回函数,当带触摸的串口屏,点击
    的头像 发表于 07-23 16:32 917次阅读
    大彩讲堂:VisualHMI-LUA教程-on_press<b class='flag-5'>回</b><b class='flag-5'>调</b><b class='flag-5'>函数</b>使用指南

    大彩讲堂:VisualHMI-LUA教程-on_run函数使用指南

    一、适合范围本文档适用于VisualHMI平台,Lua脚本语言为V5.3版本,配合工程可以完成大部分的内部逻辑处理。二、概述on_run(screen)周期函数,用该回
    的头像 发表于 07-23 15:25 910次阅读
    大彩讲堂:VisualHMI-LUA教程-on_run<b class='flag-5'>回</b><b class='flag-5'>调</b><b class='flag-5'>函数</b>使用指南

    为什么中断函数中不能使用接收中断开启函数

    我看(书是基于stm32f407编写)书上说在串口接收中断函数里面不能使用 接收中断开启函数,书上是利用自己创建了空闲中断
    发表于 05-28 07:19

    如何使用自定义设置函数

    你好,我正在尝试编写自己的自定义设置函数,并使用 fastEnum=false。 是否有任何代码示例或资料可供我参考? void CyU3PUsbRegisterSetupCallback
    发表于 05-21 06:11

    cyusb3014的usbTouart的dma通道配置,请问为什么函数无法触发?

    请问为什么函数无法触发?Why can\'t the callback function be triggered?
    发表于 05-06 08:13

    为什么中断函数中不能使用接收中断开启函数

    我看(书是基于stm32f407编写)书上说在串口接收中断函数里面不能使用 接收中断开启函数,书上是利用自己创建了空闲中断
    发表于 04-22 08:19

    为什么不需要给函数传递参数

    函数C语言里面一个重要机制。
    的头像 发表于 04-15 10:11 618次阅读

    函数指针的六个常见应用场景

    应用场景,并结合示例代码进行讲解。01、函数:解耦代码,提高灵活性函数是嵌入式开发中最常
    的头像 发表于 04-07 11:58 1117次阅读
    <b class='flag-5'>函数</b>指针的六个常见应用场景

    解锁TSMaster fifo函数:报文读取的高效方法

    前言:TSMaster目前有两种读取报文的模式:函数模式和fifo模式。fifo函数是TSMaster近期新增的函数,本文将重点介绍fi
    的头像 发表于 03-14 20:04 928次阅读
    解锁TSMaster fifo<b class='flag-5'>函数</b>:报文读取的高效方法

    EE-128:C语言中的DSP:从C调用汇编类成员函数

    电子发烧友网站提供《EE-128:C语言中的DSP:从C调用汇编类成员函数.pdf》资料免费下载
    发表于 01-07 13:48 0次下载
    EE-128:<b class='flag-5'>C</b><b class='flag-5'>语言</b>中的DSP:从<b class='flag-5'>C</b>调用汇编类成员<b class='flag-5'>函数</b>