回调函数 —— 借助中间通用函数(形参里有函数指针,实现函数注册)调用不同的回调函数 (多态/分层)

回调函数传参:函数指针做函数参数(回调函数)

目录

    • 背景
    • 回调函数是实现函数分层且单向依赖的好办法,使用函数指针运行
    • struct结构体回调函数代码更清晰
    • 简单理解回调函数
    • Demo
    • 其他回调函数博文

背景

这是我在实际工作中遇到的问题:

线程创建 第三个参数 函数指针
完全不管具体实现什么功能,把地址传过来,完全分层,黑盒子在这里插入图片描述
涂鸦:那个接口有我解析的代码,也有mcu调用者的代码,耦合在一起了
要完全分层,双方代码要放在不同的 .c 文件里面,互不干扰(比如各自OTA)。在这里插入图片描述

回调函数是实现函数分层且单向依赖的好办法,使用函数指针运行

回调函数是实现函数分层且单向依赖的好办法,使用函数指针运行:
视频讲解【回调函数和函数指针】干货分享,彻底摆脱回调地狱

在这里插入图片描述
在这里插入图片描述

实际工作中很常见的一种方法是,额外去写一个注册/安装函数:
在这里插入图片描述

在这里插入图片描述

传递参数,底层给上层传递参数:

在这里插入图片描述
在这里插入图片描述

同时上层也可以给底层一个返回值,实现数据双向的携带:

在这里插入图片描述
在这里插入图片描述

总结:
在这里插入图片描述

struct结构体回调函数代码更清晰

参考:C/C++ struct 的回调函数使用技巧
地址:https://blog.csdn.net/u010333084/article/details/51339469?spm=1001.2014.3001.5502

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

使用struct 回调函数可以使得代码更加清晰明了.

1.定义回调函数的原型

 
typedef int STRU_FU;STRU_FU sfun1(int a, const char *b){printf("fun1  a = %d , b = %s \n",a,b);return a;
}STRU_FU sfun2(int a, void *b,float c){printf("fun2  a = %d , b = %f \n",a,c);return a;
}STRU_FU sfun3(int a, char b,long c){printf("fun3  a = %d , *b = %ld \n",a,c);return a;
}

2. 定义的struct的回调函数

struct fun_ops{ //定义回调函数structSTRU_FU (*fun1)(int a, char *b); //注册参数STRU_FU (*fun2)(int a, void *b,float c);STRU_FU (*fun3)(int a, char b,long c);
};

3. 注册回调函数

struct fun_ops fuops = {//注册初始化函数指针的函数.fun1 = sfun1,.fun2 = sfun2,.fun3 = sfun3,
};

4.完整的代码

#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <stdlib.h>typedef int STRU_FU;STRU_FU sfun1(int a, const char *b){printf("fun1  a = %d , b = %s \n",a,b);return a;
}STRU_FU sfun2(int a, void *b,float c){printf("fun2  a = %d , b = %f \n",a,c);return a;
}STRU_FU sfun3(int a, char b,long c){printf("fun3  a = %d , *b = %ld \n",a,c);return a;
}struct fun_ops{ //定义回调函数structSTRU_FU (*fun1)(int a, char *b); //注册参数STRU_FU (*fun2)(int a, void *b,float c);STRU_FU (*fun3)(int a, char b,long c);
};struct fun_ops fuops = {//初始化函数指针的函数.fun1 = sfun1,.fun2 = sfun2,.fun3 = sfun3,
};int main(int argc,  char* argv[])
{int g;struct fun_ops *ops = NULL;if(argc < 2){printf("please input 1 or 2 or 3 for test fun \n");return -1;}if(strcmp(argv[1], "1") == 0){ops = &fuops;g =1;printf("fun1 \n");ops->fun1(111,"fun1");//调用回调}else if( !strcmp(argv[1], "2")){ops = &fuops;g= 2;printf("fun2 \n");ops->fun2(2222,"fun2",3333);}else{ops = &fuops;g = 3;printf("fun3 \n");ops->fun3(1212,'y',9999999);}
}

简单理解回调函数

在这里插入图片描述

你到一个商店买东西,刚好你要的东西没有货,于是你在店员那里留下了你的电话,过了几天店里有货了,店员就打了你的电话,然后你接到电话后就到店里去取了货。

在这个例子里,你的电话号码就叫回调函数,你把电话留给店员就叫登记回调函数,店里后来有货了叫做触发回调事件,店员给你打电话叫做调用回调函数,你到店里去取货叫做响应回调事件

通过上面的例子我们有了以下几点概念

  • 主函数:相当于整个程序的引擎,调度各个函数按序执行

  • 回调函数:一个独立的功能函数

  • 中间函数(通用):一个介于主函数和回调函数之间的函数,登记回调函数,通知主函数,起到一个桥梁的作用

在中间函数调用回调函数的时候,我们需要把回调函数当作参数来传递,那么就需要用到函数指针,下面以一个例子来详细了解。

Demo

#include <stdio.h>//回调函数1  不同的调用者提供 类似多态
int callBack1(int x)
{return x*2;
}
//回调函数2  不同的调用者提供 类似多态
int callBack2(int x)
{return x/2;
}
//中间函数(通用)      //函数指针
int calc(int b,int (* func)(int))   //func把函数当作参数来进行传递
{return 100+func(b);
}int main()
{int a=10;int q=calc(2,callBack1);//注册:把函数赋值给函数指针的操作就是函数注册printf("%d\n",q);int p=calc(4,callBack2);//注册&调用回调函数printf("%d\n",p);return 0;
}

运行结果:
在这里插入图片描述

分析一下代码流程

  • 1、主函数需要调用回调函数

  • 2、中间函数登记回调函数

  • 3、触发回调函数事件

  • 4、调用回调函数

  • 5、响应回调事件

其他回调函数博文

c语言回调函数的使用及实际作用详解

C语言回调函数详解(全网最全)

回调函数是什么,如何使用以及函数的注册

C语言 | 嵌入式重点知识之回调函数

在函数中调用函数,有点象递归,递归调用的是自己。

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

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

相关文章

linux下用户操作

在linux中添加ftp用&#xff0c;并设置相应的权限&#xff0c;操作步骤如下&#xff1a; 1、环境&#xff1a;ftp为vsftp。被限制用户名为test。被限制路径为/home/test。 2、建用户&#xff1a;在root用户下&#xff1a; useradd -d /home/test test //增加用户test&#…

Venkat 演讲翻译:你要清除代码中的异味

今天&#xff0c;Venkat Subramaniam 就关于清除代码异味的话题给我们做了一个非常有趣的演讲。下面就是我记录的一些他的话。 为什么我们需要有质量的代码&#xff1f; 敏捷开发方法是用来应付那些要求代码做大量改动的反馈信息的方法。如果程序没有用一种好的表达方式来表现&…

ESP8266等模块

模块讲解学习视频可参照&#xff1a;https://space.bilibili.com/323745961?spm_id_from333.788.b_765f7570696e666f.1 作者&#xff1a;叁议电子 目录ESP8266 WIFI模块介绍电脑操作ESP8266单片机上网ESP8266 WIFI模块介绍 电脑操作ESP8266 单片机上网

html5在线音乐列表播放器,HTML5列表音乐播放器SMusic

插件描述&#xff1a;一款基于HTML5、Css3的列表式音乐播放器&#xff0c;包含列表&#xff0c;音量&#xff0c;进度&#xff0c;时间&#xff0c;歌词展示以及模式等功能&#xff0c;不依赖任何库SMusic使用方法这是一款基于HTML5以及CSS3的列表式音乐播放器&#xff0c;增加…

unzipping/Users/xq/.gradle/wrapper /dists/gradle-3.3-all/55gk2rcmfc6p2dg9u9ohc3hw9/gradle-3.3-all.zi

unzipping/Users/xq/.gradle/wrapper /dists/gradle-3.3-all/55gk2rcmfc6p2dg9u9ohc3hw9/gradle-3.3-all.zip to /Users/xq/.gradle/wrapper/dists/gradle-3.3-all/55gk2rcmfc6p2dg9u9ohc3hw9 可能是下载时网络原因造成文件缺失 解决方法&#xff1a; cd /Users/xq/.gradle/w…

WIFI小车APP

对应这篇文章&#xff1a;433M射频遥控灯、震动感应灯、WIFI避障小车 目录代码概要activity_contrl.xmlContrlActivity.javaNetUtils.java详细工程代码下载代码概要 activity_contrl.xml <RelativeLayout xmlns:android"http://schemas.android.com/apk/res/android&qu…

[Web App]必胜客宅急送产品设计思路介绍[转]

O2O模式是餐饮业在移动消费趋势下主动拥抱互联网的方向&#xff0c;迎合餐饮消费者从以往经验判断为主转变为依靠移动设备、LBS、社交网络进行立体决策的过程。App成为联系消费者和餐饮业的重要纽带&#xff0c;承载着在O2O双向流程的闭环中加深消费者对品牌的认同和感情认知的…

yara 模式匹配 android,YARA——恶意软件模式匹配利器

YARA是一款旨在帮助恶意软件研究人员识别和分类恶意软件样本的开源工具(由virustotal的软件工程师Victor M. Alvarezk开发)&#xff0c;使用YARA可以基于文本或二进制模式创建恶意软件家族描述信息&#xff0c;当然也可以是其他匹配信息。YARA的每一条描述或规则都由一系列字符…

12.6今日任务

查询资料&#xff0c;查询如何包装成软件转载于:https://www.cnblogs.com/IENHOLT/p/10147742.html

C语言extern关键字(去使用外部全局变量、函数)

参考&#xff1a;C语言正确使用extern关键字 作者&#xff1a;xingjiarong 发布时间&#xff1a;2015-08-14 08:37:33 网址&#xff1a;https://blog.csdn.net/xingjiarong/article/details/47656339 目录1、引用同一个文件中的变量2、引用另一个文件中的变量3、引用另一个文件…

使用Raphael实现html中绘图

2019独角兽企业重金招聘Python工程师标准>>> 首先&#xff1a;下载Raphael的javascript库&#xff1a;http://raphaeljs.com/。或者在html页面<head></head>&#xff1a;如下 <script src"http://www.zfanw.com/blog/raphael.js"></…

ITSS认证对企业的意义

在数字化时代&#xff0c;信息技术已经成为企业发展的重要驱动力。ITSS&#xff08;信息技术服务标准&#xff09;认证&#xff0c;作为信息技术服务领域的权威认证&#xff0c;对企业的意义非凡。本文将从提高服务质量、提升企业竞争力、优化管理体系、保障信息安全等方面&…

vivo手机刷机鸿蒙,捡到vivo手机如何刷机

捡到手机&#xff0c;首先建议归还给失主&#xff01;然后如果需要刷机的话&#xff0c;建议可以清除账户密码&#xff1a;可以尝试在手机关机状态同时按住音量上键以及电源键3到4秒手机出现vivo手机标志后&#xff0c;放开按键进入recovery模式&#xff0c;先选择wipe data/fa…

UEditor 百度富文本编辑器 .Net实例

转自 http://download.csdn.net/download/hdsslxl/6740605 1、UEditor 百度富文本编辑器完整版 .Net实例 已解决上传图片问题。 2、内附完整demo实例&#xff0c;附带txt讲解说明及UEditor常见问题解决方案。 3、已经调试好的百度文本编辑器实例&#xff0c;用户体验不错&#…

详解ROM和RAM

参考&#xff1a;详解ROM和RAM 作者&#xff1a;嵌入式实验楼 网址&#xff1a;https://mp.weixin.qq.com/s/FhUxMLeAxkhWe5m-gV_hMw 目录1、只读存储器&#xff1a;ROM2、随机访问存储器&#xff1a;RAM内存是计算系统最重要的元素&#xff0c;因为没有它&#xff0c;计算机就…

ubuntu解压和压缩文件

.tar 解包&#xff1a;tar xvf FileName.tar打包&#xff1a;tar cvf FileName.tar DirName&#xff08;注&#xff1a;tar是打包&#xff0c;不是压缩&#xff01;&#xff09;———————————————.gz解压1&#xff1a;gunzip FileName.gz解压2&#xff1a;gzip -d…

python递归查询并列出目录

第一种方法&#xff1a;>>> import os #导入模块 >>> os.walk(/tmp/test/testdir) #os的walk函数对象 <generator object walk at 0x1e8a960> >>> for i in os.walk(/tmp/test/testdir): #for循环打印出目录的文件 ... print i ... (/tmp…

html 输入框防止自动记忆,网页输入框input填写内容自动记忆功能怎么去除

我们在做前端的html网页模板的时候&#xff0c;免不了要制作一些输入框&#xff0c;供使用者输入信息实现人机交互。一般情况下我们都会使用如下的HTML代码来生成单行输入框&#xff1a;这是一个很简单的HTML代码&#xff0c;其效果就是可以在前端页面输出一个输入框供用户输入…

深入理解STM32内存管理

更多干货推荐可以去牛客网看看&#xff0c;他们现在的IT题库内容很丰富&#xff0c;属于国内做的很好的了&#xff0c;而且是课程刷题面经求职讨论区分享&#xff0c;一站式求职学习网站&#xff0c;最最最重要的里面的资源全部免费&#xff01;&#xff01;&#xff01;点击进…

django ORM中的RelatedManager(关联管理器)

关联管理器应用在 一对多的表 或者 多对多的表 多对多表中的用法: 在多对多的表中 正向查询 #基于对象的查询 #正查 # author_obj Author.objects.get(id1) # print(author_obj) #<Author object: 1 吴晓波> # print(author_obj.book_set.all()) #出版过的所有的书 …