回调函数的应用实践 (1)

1,什么是回调函数?

回调函数实质上是对函数指针的实践应用。

函数指针:

函数指针是一个变量,它存储了一个函数的地址。当将函数指针作为参数传递给另一个函数时,另一个函数就可以使用这个指针来调用该函数。

定义:
int (*method_call_type)(int a,int b);类型 (*函数名)(参数列表);
最基本使用方法:
#include <stdio.h>
int (*method_call_type)(int a,int b);//定义函数指针int add(int a,int b)
{printf("add\n");return a+b;
}void main()
{printf("正常调用 add 结果 = %d \n",add(3,4));//正常调用method_call_type=add;printf("函数指针调用 method_call_type(add) 结果 = %d \n",method_call_type(3,4));//函数指针调用;
}
执行结果:
[root@localhost ~]# gcc functest.c 
[root@localhost ~]# ./a.out 
add
正常调用 add 结果 = 7 
add
函数指针调用 method_call_type(add) 结果 = 7 
[root@localhost ~]# 

2,我对回调函数应用的理解:

1,便于大型软件架构模块之间的解耦,也就是代码实现低耦合的一个方式。

2,便于大型软件架构模块划分,能使模块功能更加清晰。

大型软件框架一般都是分多模块分别编译,假设模块A对外提供函数接口,其他模块使用A的接口时需要使用A定义的结构体构造参数,如果接口改变或者参数结构体变化时。A模块代码更新了相关内容,其他模块使用A接口的地方没有改变,如果没有定义好那么会出现编译问题。但是如果做一个回调模块,A把接口功能都注册到回调模块(必须是公共模块),其他模块只需要引用回调模块的头文件和路径就行。这个时候A变更接口时只需要变更回调模块实现就行,其他模块就算不更新回调相关内容也不会出现编译问题。这个其实就是使用回调模块对其他模块做了个适配层,其他模块编译时不需要关心别的模块的影响(大不了就是某个模块的回调功能不可用)。

3,回调回调,就是来回调用的意思。回调函数可以提供一个函数集合,用户可以在程序运行的同一个点通过不同的需求来调用相同的回调函数来提供不同的函数方法。

我的理解,回调函数的使用一般在程序执行过程中的某个点,这个点有些特殊要求,比如一个数学运算集合(加减乘除),a同学执行到这个点需要做加法,b同学走到这个点需要做减法。因为这个点可能时a来,也可能时b来,对这个点执行的动作有不同的要求。那么这个时候就需要回调函数来处理。

实践1,简单的回调

定义一组数学方法,根据方法不同调用不同的数学实现。

举个例子:

main函数可以改成一般的函数,然后放到模块的需要的地方,就可以实现上面说的:不同条件运行到这个点可以提供不同的方法。

#include <stdio.h>
#include <stdlib.h>int add(int a,int b)
{printf("add\n");return a+b;
}int minus(int a,int b)
{printf("minus\n");return a-b;
}int multi(int a,int b)
{printf("multi\n");return a*b;
}int divid(int a,int b)
{printf("divid\n");return a/b;
}
/*回调过程定义----------start----------------------------------------------*/
enum
{E_ADD_METHOD,E_MIN_METHOD,E_MUL_METHOD,E_DIV_METHOD,E_MAX
};typedef int (*method_call_type)(int a,int b); //定义回调函数指针typedef struct
{method_call_type do_func;
}CALLBACK_TABLE_ST;CALLBACK_TABLE_ST g_methmatics_call_table[E_MAX] = 
{[E_ADD_METHOD] = {.do_func = add},[E_MIN_METHOD] = {.do_func = minus},[E_MUL_METHOD] = {.do_func = multi},[E_DIV_METHOD] = {.do_func = divid},
};int methodcall_execute(int method,int a,int b)
{if( method>E_MAX || method < 0){printf("method error!\n");return 1;}if(g_methmatics_call_table[method].do_func){g_methmatics_call_table[method].do_func(a,b);}
}
/*回调过程定义----------end----------------------------------------------*/
void main(int argc, char* argv[])
{int a,b,c=0;int method = 0;if(argc<4){printf("need two argvs!\n");return;}a= atoi(argv[1]);b= atoi(argv[2]);method= atoi(argv[3]);switch(method){case E_ADD_METHOD:printf(" method add   [%d+%d=%d]\n",a,b,add(a,b));break;case E_MIN_METHOD:printf(" method minus [%d-%d=%d]\n",a,b,minus(a,b));break;case E_MUL_METHOD:printf(" method multi [%d*%d=%d]\n",a,b,multi(a,b));break;case E_DIV_METHOD:printf(" method divid [%d/%d=%d]\n",a,b,divid(a,b));break;default:break;}printf("-------callbacktest!------\n");printf("result %d\n",methodcall_execute(method,a,b));return;
}
运行结果:
[root@localhost callbacktest]# ./test 8 2
need two argvs!
Segmentation fault
[root@localhost callbacktest]# ./test 8 2 1
minusmethod minus [8-2=6]
-------callbacktest!------
minus
result 6
[root@localhost callbacktest]# ./test 8 2 2
multimethod multi [8*2=16]
-------callbacktest!------
multi
result 16
[root@localhost callbacktest]# ./test 8 2 3
dividmethod divid [8/2=4]
-------callbacktest!------
divid
result 4
[root@localhost callbacktest]# ./test 8 2 4
-------callbacktest!------
result 0
[root@localhost callbacktest]# ./test 8 2 0
addmethod add   [8+2=10]
-------callbacktest!------
add
result 10

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

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

相关文章

Uni-App-03

登录功能开发 实现POST提交 HTTP协议规定请求消息内容类型(Content-Type)有哪些&#xff1f;—— 只有四种 text/plain 没有编码的普通数据 application/x-www-form-urlencoded 编码后的普通数据 multipart/form-data 请求主体中包含文件上传域 application/json 请求主体是 J…

【云原生网关】Higress 从部署到使用详解

目录 二、网关概述 2.1 什么是云原生网关 2.2 常见的云原生网关 2.2.1 Nginx 2.2.2 ApiSix 2.2.3 Kong 2.2.4 Apache Shenyu 2.2.5 Higress 2.2.6 Envoy​​​​​​​ 三、higress介绍 3.1 什么是higress 3.2 Higress 定位 3.3 Higress 内核选择 四、Higress搭…

Vscode + EIDE +CortexDebug 调试Stm32(记录)

{// 使用 IntelliSense 了解相关属性。 // 悬停以查看现有属性的描述。// 欲了解更多信息&#xff0c;请访问: https://go.microsoft.com/fwlink/?linkid830387"version": "0.2.0","configurations": [{"cwd": "${workspaceRoot…

阿里面试竟被“DPO微调”吊打...

最近已有不少大厂都在秋招宣讲&#xff0c;也有一些已在 Offer 发放阶段了。 节前&#xff0c;我们邀请了一些互联网大厂朋友、今年参加社招和校招面试的同学。 针对新手如何入门算法岗、该如何准备面试攻略、面试常考点、大模型技术趋势、算法项目落地经验分享等热门话题进行…

一个可以调节笔记本亮度的程序

在我这台笔记本上&#xff0c;当我把显示模式调为读显时发现右下角的亮度不能调了&#xff0c;就像这样 听说时nvidia显卡不适配的问题 咱也不知道呀 于是我就用java写了程序来调节&#xff0c;用了俩个多月&#xff0c;没啥问题的 打开就是这样拉动直接就可以调节 源码 im…

unity中的组件(Component)

在 Unity 中&#xff0c;组件&#xff08;Component&#xff09;是构成 GameObject 功能和行为的基础单元&#xff0c;每个 GameObject都可以附加一个或多个组件&#xff0c;以实现不同的功能 1. Transform 组件 描述&#xff1a;所有 GameObject 默认都有一个 Transform 组件…

C++研发笔记8——C语言程序设计初阶学习笔记6

在第一部分——课前准备的学习中&#xff0c;我就提到了学习C语言的过程中&#xff0c;练习是必不可少的环节&#xff0c;所以本篇笔记我们来进行记录我们学习《C语言程序设计初阶》阶段的第一篇练习文章。 题目一 下面哪个不是C语言内置的数据类型&#xff1a; A.char B.d…

【大数据学习 | kafka】kafuka的基础架构

1. kafka是什么 Kafka是由LinkedIn开发的一个分布式的消息队列。它是一款开源的、轻量级的、分布式、可分区和具有复制备份的&#xff08;Replicated&#xff09;、基于ZooKeeper的协调管理的分布式流平台的功能强大的消息系统。与传统的消息系统相比&#xff0c;KafKa能够很好…

C++基础:三个字符串也能搞大小?

上一篇说了三个整数比较大小&#xff0c;按照顺序输入的&#xff0c;这次我们看看字符串的&#xff0c;顺便把那个简化以下&#xff1a; 题目:这次输入三个字符串。如果用户输入“Stenbeck", “Hemingway”,“Fitzgerald”,输出将是“Fitzgerald&#xff0c;Hemingway&…

OPPO携手比亚迪共同探索手机与汽车互融新时代

10月23日&#xff0c;OPPO与比亚迪宣布签订战略合作协议&#xff0c;双方将共同推进手机与汽车的互融合作&#xff0c;这一合作也标志着两大行业巨头在技术创新和产业融合上迈出了重要一步&#xff0c;为手机与汽车的深度融合探索新的可能。 OPPO创始人兼首席执行官陈明永、OP…

LCD手机屏幕高精度贴合

LCD手机屏幕贴合&#xff0c;作为智能手机生产线上至关重要的一环&#xff0c;其质量直接关乎用户体验与产品竞争力。这一工艺不仅要求屏幕组件间的无缝对接&#xff0c;达到极致的视觉与触觉效果&#xff0c;还需确保在整个生产过程中&#xff0c;从材料准备到最终成品&#x…

<Project-11 Calculator> 计算器 0.3 年龄计算器 age Calculator HTML JS

灵感 给工人发工资是按小时计算的&#xff0c;每次都要上网&#xff0c;我比较喜欢用 Hours Calculator &#xff0c;也喜欢它的其它的功能&#xff0c; 做个类似的。 我以为是 Python&#xff0c;结果在学 javascript 看 HTML&#xff0c;页面的基础还停留在 Frontpage 2000…

MongoDB简单学习

MongoDB 一、基本使用 1.1业务应用场景 传统的关系型数据库&#xff08;如Mysql&#xff09;&#xff0c;在数据库操作的“三高”需求以及对应web2.0的网站需求面前&#xff0c;显得力不从心 三高&#xff1a; High performance - 对数据库高并发读写的要求Huge Storage -…

1U服务器和Hyper-V虚拟机使用记录

记录最近接触服务器和虚拟机的一些使用操作知识 背景&#xff1a;1U服务器上架使用&#xff0c;备份其他服务器vm虚拟机&#xff0c;Hyper-V管理虚拟机使用测试 设备&#xff1a;IBM3550服务器交换机&#xff0c; 移动硬盘&#xff1a;附加存储盘&#xff0c; u盘1&#xff1…

解决JAVA使用@JsonProperty序列化出现字段重复问题(大写开头的字段重复序列化)

文章目录 引言I 解决方案方案1:使用JsonAutoDetect注解方案2:手动编写get方法,JsonProperty注解加到方法上。方案3:首字母改成小写的II 知识扩展:对象默认是怎样被序列化?引言 需求: JSON序列化时,使用@JsonProperty注解,将字段名序列化为首字母大写,兼容前端和第三方…

【C++】进阶:类相关特性的深入探讨

⭐在对C 中类的6个默认成员函数有了初步了解之后&#xff0c;现在我们进行对类相关特性的深入探讨&#xff01; &#x1f525;&#x1f525;&#x1f525;【C】类的默认成员函数&#xff1a;深入剖析与应用&#xff08;上&#xff09; 【C】类的默认成员函数&#xff1a;深入剖…

【从零开始的LeetCode-算法】910. 最小差值 II

给你一个整数数组 nums&#xff0c;和一个整数 k 。 对于每个下标 i&#xff08;0 < i < nums.length&#xff09;&#xff0c;将 nums[i] 变成 nums[i] k 或 nums[i] - k 。 nums 的 分数 是 nums 中最大元素和最小元素的差值。 在更改每个下标对应的值之后&#xf…

论文略读:Not all Layers of LLMs are Necessary during Inference

202404 LLMs的推理阶段非常昂贵 目前实现LLM高效推理的流行方法包括模型剪枝和稀疏模型 但这些方法可能会改变LLM参数&#xff0c;从而冒险损害其泛化能力。这篇论文动态减少激活神经元的数量以加速LLM推理 根据输入实例动态决定推理终止时刻

openjdk17在java方法中创建对象 类加载在C++源码实现步骤

java的testYYM方法中OtherClass类是如何被加载的 ##有请志愿者java实验类 ByteCodeTest、OtherClass import java.lang.reflect.Method;public class ByteCodeTest {private int insert678;public static void main(String[] args) throws Exception {ByteCodeTest byteCodeT…

leetcode动态规划(十三)-目标和

题目 494.目标和 给你一个非负整数数组 nums 和一个整数 target 。 向数组中的每个整数前添加 或 - &#xff0c;然后串联起所有整数&#xff0c;可以构造一个 表达式 &#xff1a; 例如&#xff0c;nums [2, 1] &#xff0c;可以在 2 之前添加 &#xff0c;在 1 之前添…