C 回调函数的两种使用方法

        对回调(callback)函数的一点粗陋理解,在我小时候,隔壁村有家月饼小作坊(只在中秋那段时间手工制作一些月饼出售,后来好像不做了),做出的月饼是那种很传统很经典的款式,里面有红绿丝、冰糖以及芝麻(好像也只做这一种),曾经跟着大人进去过一次,里面有张木头制作的月饼模子,原来花瓣状的月饼是用它压出来的啊,我们的回调函数(指针)就是这张月饼模子。功能是制作月饼(函数返回值),配料(参数)是面粉和油以及馅料。假如这个作坊一共有3个工人,每个工人负责一种馅料(五仁、豆沙、蛋黄)月饼,他们都需要这张月饼模子来制作自己的月饼,换句话说,他们都要提供同样类型的参数(配料)并得到同样类型的结果(月饼),至于具体的里子和做法(函数实现)必须得他们个人定,在实际生产(程序流程)中,这仨工人按各自节奏准备好自己的物料(函数实现),当在需要制作月饼时(调用回调函数),将配料往模子里这么一压,哟嘿,糯和和的月饼制作出来了。

        这一天当中,不同的师傅拿这个模子(回调函数指针)按自己的方法(函数具体实现)塞入配料(参数)压出了不同口味的月饼,不知道有没有越描越糊涂的嫌疑。

        下面再简单说说两个比较常见的用法。

例子一

一般使用(理解概念)
#include<stdio.h>

int Callback_1(char *m) // Callback Function 1
{
    printf("Hello, this is Callback_1 %s\n", m);
    return 0;
}

int Callback_2(char *n) // Callback Function 2
{
    printf("Hello, this is Callback_2 %s\n", n);
    return 0;
}

int Callback_3(char *t) // Callback Function 3
{
    printf("Hello, this is Callback_3 %s\n", t);
    return 0;
}

int Handle(int (*Callback)(char *), char *val)
{
    printf("Entering Handle Function. \n");
    Callback(val);
    printf("Leaving Handle Function. \n");
}

int main()
{
    printf("Entering Main Function. \n");
    Handle(Callback_1, "wuren");
    Handle(Callback_2, "dousha");
    Handle(Callback_3, "danhuang");
    printf("Leaving Main Function. \n");
    return 0;
}

        上面的代码中,月饼模子就是int (*Callback)(char *),返回值是int(月饼),参数是char *(配料),三个师傅各自的秘密配方及手法分别是int Callback_1(char *m)、int Callback_2(char *n)、int Callback_3(char *t),这个int Handle(int (*Callback)(char *), char *)函数就是标准的工艺流程。在制作时(主函数内部调用),我们让师傅们轮流来操作,一号师傅拿起"wuren"配料制作出了五仁月饼,二号师傅拿起“dousha”配料制作出了豆沙月饼,三号师傅拿起"danhuang"配料制作出了蛋黄月饼。返回情况如下。

例子二

结构体使用(使用拓展)
#include <stdio.h>

typedef struct
{
    int w;
    int h;
    int (*callback)(void*, void*);    
}St_Rect;

int area(int w, int h)
{
    if(w && h)
    {
        return w*h;
    }
    else
    {
        printf("area:invalid para!\n");
        return -1;
    }
     
}

int perimeter(int w, int h)
{
    if(w && h)
    {
        return 2*(w + h);
    }
    else
    {
        printf("perimeter:invalid para!\n");
        return -1;
    }
}

int empty(int w, int h)
{
    printf("w=%d,h=%d\n", w, h);
    return 0;
}

void main(void)
{
    St_Rect rect;
    int choose = -1;
    
    printf("please input w\n");
    scanf("%d", &rect.w);
    printf("please input h\n");
    scanf("%d", &rect.h);
    
    printf("please input choose result\n");
    scanf("%d", &choose);
    
    switch(choose)
    {
        case 0:
            rect.callback = area;
            break;
        case 1:
            rect.callback = perimeter;
            break;
        default:
            rect.callback = empty;
            break;
    }
    
    int result = rect.callback((int *)rect.w, (int *)rect.h);
    printf("the result is %d\n", result);
}

        这段代码则是回调函数的另外一种用法,很多实际项目上应该都比较常见。比如一家研发金融产品的公司,他们的客户有人行、建行、农行等等国内外银行以及其他机构,其中这家公司的一款清分机市场销量挺nice,吸引了更多的客户来购买,但是不同的客户有不同的需求(清分数据的处理逻辑),之前只有几家客户的情况下还可以通过类似if else、switch case这样的方法来实现不同客户的需求,随着客户数量的增加,再这么干不是不可以,但你能忍受代码里有这么多的条件语句吗,而且代码整体看起来码商也不高。此时我们就可以考虑用回调(第一种使用方法的升级用法),共用同一套架构,初始化时给予不同的函数实现。上面的代码例子也是基于此种场景,我们来看看。

        我们定义了一个矩形结构体,成员变量有宽度w、高h以及一个我们的回调函数指针int (*callback)(void*, void*),这个函数指针等同于保存一个(函数)地址的变量,而且这个回调函数有两个无类型的参数void*,无类型方便我们后面拓展使用。主函数内,我们让使用者分别输入宽度和高度值,并在最后让使用者选择是生成矩形面积结果呢还是矩形周长结果。其中的switch语句相当于初始化过程,确定最终的客户方案,最后开始了我们的回调过程,并返回我们选择的方案结果。

        大家在日常工作学习中如有类似需求可以参考一二,如果还有其他用法,欢迎告知讨论!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C 练习实例97 - 读磁盘 写磁盘

题目&#xff1a;从键盘输入一些字符&#xff0c;逐个把它们送到磁盘上去&#xff0c;直到输入一个‘#’为止 在桌面新建一个hello.txt文件&#xff0c;内容示例&#xff1a; 代码&#xff1a; #include <stdio.h> #include <stdlib.h>int main() {FILE *fp; //文…

CSS样式-字体类型,文本对齐,外观修饰,文本缩进,文本行间距,外部引用css样式

字体类型和字体属性调整 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Css字体类型大小</title&…

【软路由】iStoreOS全量备份或数据迁移思路

背景&#xff1a;之前是在我的i3小主机上面搭建了iStoreOS&#xff0c;因为有段时间爱折腾&#xff0c;于是乎不知道什么情况就造成首页无法登录&#xff0c;改了的东西无法回滚&#xff0c;好在使用“万能重启”法又可以登录了&#xff0c;于是我就在想把这玩意定期备份一下。…

算法打卡day25

今日任务&#xff1a; 1&#xff09;491.递增子序列 2&#xff09;46.全排列 3&#xff09;47.全排列 II 491.递增子序列 题目链接&#xff1a;491. 非递减子序列 - 力扣&#xff08;LeetCode&#xff09; 给定一个整型数组, 你的任务是找到所有该数组的递增子序列&#xff0c…

选数异或(DP)

题目描述 给定一个长度为 n 的数列 A1, A2, , An 和一个非负整数 x&#xff0c;给定 m 次查询, 每次询问能否从某个区间 [l,r] 中选择两个数使得他们的异或等于 x 。 输入格式 输入的第一行包含三个整数 n, m, x 。 第二行包含 n 个整数 A1, A2, , An 。 接下来 m 行…

Redis高可用技术

一.Redis高可用介绍&#xff1a; 高可用是指&#xff1a;服务器正常访问的时间 衡量的标准是&#xff1a;在多长时间内可以提供正常服务99.9%、99.99%、99.999%等等 但是在Redis语境中&#xff0c; 高可用的含义似乎要宽泛一些&#xff0c;除了保证提供正常服务(如主从分离、…

Find a way (DFS BFS)

//新生训练 #include <iostream> #include <algorithm> #include <queue> using namespace std; using PII pair<int, int>;const int N 205; const int inf 0x3f3f3f3f; int n, m; int l;int dis1[N][N]; int dis2[N][N];int dx[] {0, 0, -1, 1};…

springboot实战---6.项目发布

&#x1f388;个人主页&#xff1a;靓仔很忙i &#x1f4bb;B 站主页&#xff1a;&#x1f449;B站&#x1f448; &#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏 &#x1f917;收录专栏&#xff1a;Springboot &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&…

深入C语言:探究static关键字的奥秘

文章目录 一、链接属性二、static变量1、定义静态局部变量2、在函数内部使用静态变量3、函数中静态局部变量与递归 三、static变量与全局变量的区别1、存储期与生命周期2、可见性与作用域3、使用场景4、静态与动态内存分配 注意事项 当用于不同的上下文环境时&#xff0c; sta…

nginx配置多vue项目

1. 找到linux docker安装好的nginx目录文件 进入nginx内 把打包好的vue项目放在html文件下 如上 三个文件夹下对应着三个不同的vue项目 2. 配置default.conf的配置文件&#xff0c; 一个nginx配置文件可以多个项目进行代理 进入到conf 找到conf.d下面的default.conf 文件…

Springboot自动获取接口实现

ServiceLoader加载接口实现步骤 1.编写接口 public interface CommunicationAdapterFactory {void setKernel(LocalKernel kernel);boolean providesAdapterFor(Vehicle vehicle);BasicCommunicationAdapter getAdapterFor(Vehicle vehicle); }2.编写实现 // 实现类 1 publi…

EasyBoss ERP支持TikTok Shop拆单发货功能,多店铺订单包裹拆分一个系统搞定

一些TikTok Shop本土卖家在运营过程中面临这样的困境&#xff1a;当顾客一次性订购多个商品&#xff0c;由于部分商品缺货或包裹超重&#xff0c;订单延迟发货或被物流限制发不出货&#xff0c;导致店铺被投诉。为了解决这一问题&#xff0c;卖家可以采取拆单发货的策略&#x…

支持各种不同系列nvdia显卡和amd显卡,DeepFaceLab安装与使用,附完整的软件打包下载一键安装

支持各种不同系列nvdia显卡和amd显卡&#xff0c;DeepFaceLab安装与使用&#xff0c;附完整的软件打包下载一键安装。 主要使用的技术&#xff1a; 1. 深度学习&#xff08;Deep Learning&#xff09; 深度学习是人工智能领域的一个重要分支&#xff0c;它通过模拟人脑的神经…

蓝桥杯 - 正则问题

解题思路&#xff1a; dfs import java.util.Scanner;public class Main {static int pos -1; // 充当charAt下标static String s;// 字符串型的静态变量public static void main(String[] args) {Scanner scanner new Scanner(System.in);s scanner.nextLine();System.ou…

Spring Boot--文件上传和下载

文件上传和下载 前言文件上传1、以MultipartFile 接口流文件&#xff0c;流的名称需要和前台传过来的名称对应上2、获取到文件名称截取后缀3、为了放置文件名重复使用uuid来随机生成id后缀4、判断转存路径中是否有这个文件夹如果没有就创建5、将文件存储到转存的目录中 文件下载…

免费AI视频工具PixVerse厉害了:可保持人物超强一致性(附详细教程)

PixVerse 上线了「Character」&#xff0c;可以在更换场景的情况下&#xff0c;保持人物的一致性。 下面就是用创建的人物角色&#xff0c;生成的不同场景下&#xff08;海边、城市街道、教室&#xff09;的视频&#xff0c;整体看一致性程度还是超出我的预期的。 PixVerse 人物…

华为服务器RAID配置教程 服务器硬盘故障处理帮助 浪潮RAID配置教程 磁盘阵列配置通用教程

前言&#xff08;本文档持续更新&#xff09; 本文主要记录服务器配置RAID&#xff08;磁盘阵列&#xff09;过程中存在的细节问题及官方文档无法解决的问题的解决方案 配置环境 华为 RH2288 v3服务器配置RAID组 如何快速配置 1.找到服务器品牌的阵列卡型号&#xff0c;找不到…

DBU-Net:用于乳腺超声图像中肿瘤分割的双分支U形网络

DBU-Net&#xff1a;用于乳腺超声图像中肿瘤分割的双分支U形网络 摘要引言材料和方法概述所提出的方法 DBU-Net Dual branch U-Net for tumor segmentation in breast ultrasound images 摘要 乳腺超声医学图像通常具有低成像质量沿着不清楚的目标边界。这些问题使得医生在诊断…

详解k8s集群内外的访问方式

文章目录 1、集群内访问2、集群外访问2.1、Ingress转发外网请求2.2、LoadBanlancer接入外网请求2.3、NodePort接入外网请求 3、总结和对比3.1、Ingress、NodePort和LoadBalancer总结3.2、Ingress和网关的区别 1、集群内访问 在k8s中创建的微服务&#xff0c;大部分都是在集群内…

收下这份地表最强参会指南,4月16日,玩转百度Create大会不迷路

欢迎来到英杰社区&#xff1a; https://bbs.csdn.net/topics/617804998 欢迎来到阿Q社区&#xff1a; https://bbs.csdn.net/topics/617897397 &#x1f4d5;作者简介&#xff1a;热爱跑步的恒川&#xff0c;致力于C/C、Java、Python等多编程语言&#xff0c;热爱跑步&#xff…