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

2023-11-17

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

背景

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

线程创建 第三个参数 函数指针
完全不管具体实现什么功能,把地址传过来,完全分层,黑盒子在这里插入图片描述
涂鸦:那个接口有我解析的代码,也有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{ //定义回调函数struct
 
	STRU_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{ //定义回调函数struct
 
	STRU_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语言 | 嵌入式重点知识之回调函数

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

随机推荐

  • C++ 模板类 模板成员函数

    最近看了C 的sigslot库 对其里面模板类 模板成员函数的一些用法记录下 include
  • 反转字符串 反转字符串

    思想总结 首先将字符串转变为字符数组 再进行遍历并反转字符 1 反转字符串 代码 class Solution public void reverseString char s reverse s 0 s length 左闭右开 publi
  • draw.io使用教程

    大部分的绘图应用都离不开三个基本的元素 图形 链接 文本 每个元素都有基本的操作和样式 元素与元素之间又可以进行组合 三生万物 生成各种各样的图表 如果没有这款绘图的 可以点击获取 drawio文件 1 首先打开draw io deskto
  • Maven引入本地Jar包

    项目场景 有些jar包在Maven Central Repository 中没有 需要引入本地jar包 问题描述 使用本地的jar要解决两个问题 第一 引入项目中编译通过 本地开发正常启动 第二 项目打包正常 步骤 1 新建一个与src同级
  • 如何在配置文件中注释掉和取消注释行

    You may have seen instructions that tell you to uncomment or comment out lines in a configuration or source code file Th
  • vue动态绑定class和style,三目运算符条件判定

    动态绑定class和style 给绑定的class style传递一个对象 以动态切换 div div 给绑定的class传递一个数组 以应有一个class列表 三元运算 div div 数组对象 div div 给绑定的st
  • 电信光纤猫虚拟服务器设置方法,电信光纤猫怎么设置宽带拨号?

    网络运营商在装光纤宽带的时候会赠送一个光纤猫 里面的配置是工作人员预设好的 而这个光猫也带有自动拨号的功能 所以电信的光纤猫是不需要拨号的 但我们如果需要使用拨号连接宽带 该怎么设置呢 阅读下文了解电信光纤猫设置宽带拨号上网的方法 操作之前
  • 利用OpenCV的Grabcut()函数实现图像的前景与背景的分割-并对Grabcut()作详细介绍

    图像处理开发需求 图像处理接私活挣零花钱 请加微信 QQ 2487872782 图像处理开发资料 图像处理技术交流请加QQ群 群号 271891601 Graphcut是一种基于图论的分割方法 在计算机视觉领域中应用于前景分割 医学处理 纹
  • C++第二章课后习题

    如果可以 还请点个赞 2 1 C 语言有哪些主要特点和有点 解 1全面兼容c 2面向对象的方法 2 2 下列标识符有哪些是合法的 Program page lock test2 3inl mail A B C D 解 第1 3 4 7个 2
  • 用telnet来观察http协议的通信过程

    用windows下的telnet命令来观察http协议的通信过程如下 1 开始 R 在弹出对话框里输入cmd 2 以下是cmd窗口的输入输出 用户输入文本内容为红色 按键为黄色 部分内容在运行过程中可能会被清除 所以可能看到的内容跟下面不一
  • 3dmax渲染完就卡住不动怎么办?

    有很多种原因都可能会导致3DMAX卡死 需要一个个排查 一 3dmax和系统语言不兼容 解决方法是把电脑里语言设置的兼容性打开 二 3dmax内存分配不足 把动态内存限制设置到1W以上或是直接设置为0 不限制 三 渲染设置错误 可以尝试重置
  • win10利用annaconda安装tensorflow1.8.0

    之前在ubuntu安装tensorflow走过很多弯路 也重装过很多次系统 今天在windows下安装时特意请求大神支援 一次性通过 现分享经验如下 以下安装包链接 链接 https pan baidu com s 1z3fr8kH3azt
  • 如何在github上搭建自己的博客

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 之前闲暇之余尝试着在github上搭建自己的博客 搭建过程中发现没有自己想象的那么容易 几经波折 好不容易才搭建好了雏形 现在就将在github上构建自己博客的整个流程好好
  • 写一篇预制构件厂员工管理方案

    预制构件厂员工管理方案一 招聘1 招聘程序应严格按照法定程序进行 包括发布招聘公告 收集报名材料 审核 录用等 2 根据企业对员工的要求 组织专业的面试 以确定最合适的候选人 二 培训1 为新员工组织培训 介绍公司的各项政策 工作要求和工作
  • Hadoop完全分布式集群——Hadoop 配置

    前面已完成VMware虚拟机安装与配置 参考前一篇Hadoop完全分布式集群 VMware虚拟机安装与配置 夏雨和阳阳的博客 CSDN博客 下面将进行Hadoop 配置 一 slave1 slave2节点配置修改 slave1 slave2
  • 推荐 OS X 下最方便实用的六款解压缩软件

    对于我们这种资料特别多 随时都需要跟工作伙伴沟通传递资料的人来说 一款方便的压缩软件真的太重要了 不仅可以节省时间 节省内存 更重要的是提高工作效率 今天废鱼就给大家推荐几款常用压缩软件 The Unarchiver The Unarchi
  • 【华为OD统一考试B卷

    在线OJ 本题通过率100 已购买本专栏用户 请私信博主开通账号 在线刷题 运行出现 Runtime Error 0Aborted 请忽略 华为OD统一考试A卷 B卷 新题库说明 2023年5月份 华为官方已经将的 2022 0223Q 1
  • 2021全国大学生电子设计竞赛F题(智能送药小车)国一赛后总结

    作为2022年的第一篇博客 思索了很久 就以此为题吧 11月7号随着电赛比赛的结束 我的大学竞赛生涯也差不多告一段落了 那天的心情也是无法用语言形容 第二天就又回归了正常的上课生活 2021年的电赛 既让人期盼 又存在许多变数 这一切都要从
  • java日期格式化yyyy-mm-dd

    在 Java 中 你可以使用 SimpleDateFormat 类来格式化日期 以 yyyy MM dd 为例 你可以这样写 SimpleDateFormat dateFormat new SimpleDateFormat yyyy MM
  • 回调函数 —— 借助中间通用函数(形参里有函数指针,实现函数注册)调用不同的回调函数 (多态/分层)

    回调函数传参 函数指针做函数参数 回调函数 目录 背景 回调函数是实现函数分层且单向依赖的好办法 使用函数指针运行 struct结构体回调函数代码更清晰 简单理解回调函数 Demo 其他回调函数博文 背景 这是我在实际工作中遇到的问题 线程