typedef函数指针_C语言函数指针之回调函数

c3a9e96373f471ba535960e4e7bf6dd6.png

1 什么是回调函数?

首先什么是“回调”呢?

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

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

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

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

2 为什么要用回调函数?

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

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

25a1974ceeacafb2d16c8642d157a8a4.png
int Callback()    ///{
    // TODO
    return 0;
}
int main()     ///{
    // TODO
    Library(Callback);  ///    // TODO
    return 0;
}

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

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

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

3 怎么使用回调函数?

int Callback_1(int a)   ///{
    printf("Hello, this is Callback_1: a = %d ", a);
    return 0;
}

int Callback_2(int b)  ///{
    printf("Hello, this is Callback_2: b = %d ", b);
    return 0;
}

int Callback_3(int c)   ///{
    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     {
        if(Start == M26_WorkStatus_Tab[i].mStatus)
        {          
      return M26_WorkStatus_Tab[i].Funtion();
        }
    }
    return 0;
}

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

推荐阅读

C/C++函数指针与指针函数

C语言指针详解

d04b932318ccfa0108551449d27a14ba.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/550328.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

生成球 使用openMesh 库

简介 使用openmesh生成一个球&#xff0c;采用的是标准球坐标系。 // 生成球 n 最好输入偶数 10 或者 100 #include <iostream> #include <OpenMesh/Core/IO/MeshIO.hh> #include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh> #include<cmath> #d…

oracle存储过程没有返回值,Java调用Oracle存储过程(无返回值)

无返回值&#xff1a;1&#xff1a;创建存储过程此存储过程向表中插入一条数据create or replace procedure demo_procedure(id varchar2,name varchar2,age varchar2,sex varchar2,address varchar2)asbegininsert into system.demo values(id,name,age,sex,address);end;2&am…

python static函数_python函数怎么实现static变量?

展开全部python函数实现static变量具体32313133353236313431303231363533e4b893e5b19e31333365633838如下&#xff1a;def ask_ok(prompt, retries4, complaintYes or no, please!):while True:ok raw_input(prompt)if ok in (y, ye, yes): return Trueif ok in (n, no, nop, …

Linux权限管理、系统进程管理

权限管理 linux系统中分为四种角色 uuser 当前用户 ggroup 同组用户 oother 其他用户 aall 代表所有用户 三种权限 rread 可读 wwrite 可写 xexecute 可执行 通过ls -l(ll)查看文件或者目录的权限 ll a.log -rw-r--r--. 1 root root 16003 Jun 27 09:20 a.log 分析第一部…

fedora 安装oracle 12c,Fedora 12下安装Oracle 11客户端

目标&#xff1a;将oracle-client(v11)安装到rdquo;/opt/oracle/rdquo;下准备好如下三个安装包&#xff0c;放在某个目录下&#xff0c;如&#xff1a;/root/software/ora目标&#xff1a;将Oracle-client(v11)安装到”/opt/oracle/”下准备好如下三个安装包&#xff0c;放在某…

轨迹跟踪主要方法_DELMIA教程:基于指令形式的机器人TCP轨迹局部跟踪方法

上一期为大家介绍了基于工具条中的“TCP Trace”命令按钮的全局TCP轨迹跟踪&#xff0c;之所以称之为全局轨迹跟踪&#xff0c;是因为只要命令被打开&#xff0c;机器人运行的全部轨迹都将实现跟踪。既然有全局TCP轨迹跟踪&#xff0c;那么就一定有局部TCP轨迹跟踪&#xff0c;…

[转帖]开源许可证GPL、BSD、MIT、Mozilla、Apache和LGPL的区别

开源许可证GPL、BSD、MIT、Mozilla、Apache和LGPL的区别 https://www.geek-workshop.com/thread-1860-1-1.htmlliamjeal电梯直达1# 发表于 2012-9-10 13:41:43 | 只看该作者 |只看大图 因CooCox用户数及影响力越来越大&#xff0c;CooCox团队也逐渐提高了对软件及代码协议的重…

oracle数据库物理结构包含,Oracle - 数据库物理结构

● 一个数据文件只能属于一个数据库● 当数据库空间用完时&#xff0c;数据文件可以按照预定的设置自动扩展。● 一个或多个数据文件形成了数据库中的一种逻辑结构-表空间。当需要时&#xff0c;数据文件中的数据通过数据库操作被读出&#xff0c;并缓存于Oracle的内存结构中。…

python审批流系统_有赞移动关于权限与审批流程的标准化

一、背景有赞移动有weex发布平台、移动配置中心平台、App分发平台、热修复平台等。这些平台都需要发布&#xff0c;而发布就需要规范化&#xff0c;需要审批制度。如果为各个平台开发这个审批流程&#xff0c;看起来是一种浪费。首先想到第一种方案&#xff1a;接入现有的前后端…

生成一个平面矩形网格文件

简介 生成一个平面矩形网格。 代码 // CreateGrid.cpp: 定义控制台应用程序的入口点。 ////#include "stdafx.h" #include <iostream> #include <OpenMesh/Core/IO/MeshIO.hh> #include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh> #include<…

linux下tomcat脚本,Linux下重启多个 tomcat 服务的脚本(推荐)

由于修改tomcat的配置文件或手动操作数据库数据后&#xff0c;tomcat的缓存和redis的缓存很严重&#xff0c;需要经常重启tomcat来释放缓存&#xff0c;经常就是手动重启。# 1、查找tomcat的进程IDps -ef | grep tomcat# 2、根据路径去查找进程ID&#xff0c;然后逐个杀掉(毕竟…

qt 定时器累加值_零基础入门单片机定时器详解

一、基本定时器介绍在STM32中&#xff0c;基本定时器有TIM6、TIM7等。基本定时器主要包含时基单元&#xff0c;提供16位的计数&#xff0c;能计数0~65535。基本定时器除了计数功能以外&#xff0c;还能输出给DAC模块一个TRGO信号。基本定时器框图如下&#xff1a;二、时基单元介…

生成 一个多边形网格的函数

简介 生成一个多边形网格的函数。 三角形面片判断法线方向 顺时针&#xff0c;表示平面方向向下&#xff1f;&#xff1f; 逆时针&#xff0c;表示平面方向向上&#xff1f;&#xff1f; 代码 // AddPolygon.cpp: 定义控制台应用程序的入口点。 ////#include "stdafx.h&qu…

linux系统怎么设置开机密码,Linux_Linux系统怎么设置开机密码?Linux设置开机密码的方法,为了保证Linux系统的安全,应 - phpStudy...

Linux系统怎么设置开机密码&#xff1f;Linux设置开机密码的方法为了保证Linux系统的安全&#xff0c;应该给系统设置开机密码。注意&#xff0c;“开机密码”和“登录密码”是不同的。本文笔者就和大家分享一下“给Linux设置开机密码”的经验&#xff0c;希望能能对大家有所帮…

jvm 安装位置_简单了解JVM

1、JVM的位置&#xff1a;JVM是在操作系统上面的应用软件JVM虚拟机有三种如下&#xff1a;① Sun公司的HotSpot&#xff1b;    ② BEA公司的JRockit&#xff1b;    ③ IBM公司的J9 JVM&#xff1b;java虚拟机属于第一种&#xff1a;2、JVM的体系结构&#xff1a;3、类…

前端安全之 XSS攻击

参看&#xff1a; XSS的原理分析与解剖 前端安全 -- XSS攻击 web大前端开发中一些常见的安全性问题 1、前言 XSS 是面试时&#xff0c;hr提出来给我的&#xff0c;然后大体的浏览一遍&#xff0c;今天才查阅资料大体了解了它。 XSS 攻击&#xff1a;攻击者向HTML页面传入恶意的…

linux设置命令nmui,Linux网络配置及管理

一、IP、网关、路由、掩码网络间主机的通信是通常是基于TCP/IP协议。数据从A主机发送到网络中的B主机&#xff0c;需要通过层层包装及协议转发&#xff0c;最终通过B主机的IP地址定位&#xff0c;B主机才能最终接收到数据。这个过程很复杂&#xff0c;中间数据的处理是通过TCP/…

anaconda新建python2环境安装不了jupyterlab_在Mac下安装anaconda及配置jupyterLab和PyTorch的方法...

在Mac下安装anaconda及配置jupyterLab和PyTorch的方法1、 首先在anaconda官网上下载anaconda包(国内网速度不算太慢)https://www.anaconda.com/products/individual#macos2、 创建一个新的环境&#xff0c;用于Pytorch的学习conda create –name pytorchpython3.7标蓝部分可以换…

图片

转载于:https://www.cnblogs.com/water-1/p/11138418.html

idea 调节背景护眼_夜间用电脑亮瞎眼睛?这份夜间护眼指南来帮你。

题图&#xff1a;来自 Unsplash文/彭宏豪&#xff0c;笔名/安哥拉不知从什么时候起&#xff0c;「头秃」成了网友和周围人口中的一个高频词汇&#xff0c;似乎很多事情都离不了头秃——学到头秃、工作到头秃、熬夜到头秃等等&#xff0c;就连「突然」也渐渐演变成「秃然」。但对…