C/C++ 回调函数 callback 异步编程

news2025/2/3 1:08:34

一、C语言的回调函数

1.小试牛刀 

#include <iostream>
using namespace std;
#include <memory>
#include <stdlib.h>

int add(int a, int b) {
    return a + b;
}

void test01() {
    // 函数指针可以指向任何类型的函数,只要函数的参数列表和返回值类型匹配即可
    int (*pFunc)(int,int) = add;
    // 函数指针可以像普通函数一样被调用,通过函数指针变量名加上括号的方式
    int result = (*pFunc)(1,2);
    cout << result << endl; // 输出 3
}

// typedef 返回类型(*新的函数名)(参数列表)
typedef int (*INT_func)(int,int);
void test02() {
    INT_func pFunc = add;
    int result = pFunc(2,3);
    cout << result << endl; // 输出 5
}

// 回调函数,它允许一个函数作为参数传递给另一个函数
// 这种特性使得我们可以将一些特定的任务委托给其他函数来完成

// 定义一个函数指针类型
typedef void(*Callback)(int);
// 定义一个函数,该函数接受一个回调函数作为参数
void doSomething(Callback callback) {
    cout<<"Doing something..."<<endl;
    // 调用回调函数
    int data = 1024;
    callback(data);
}

// 定义一个回调函数
void printMyData(int data) {
    cout<<"My data is: "<<data<<endl;
}

int main() {
    test01();
    test02();
    // 将回调函数传递给doSomething函数
    /*
        doSomething函数接受一个Callback类型的参数,这是
        一个指向函数的指针.doSomethings函数调用这个回调函数,
        并且将一个整型变量作为参数传递给它
        printMyData在此是一个简单的回调函数,它接受一个整型变量作为
        参数并且把它打印出来
    */
    doSomething(printMyData);
    return 0;
}
  • 打印结果:
PS D:\Work\c++> ./bin/app     
3
5
Doing something...
My data is: 1024
PS D:\Work\c++>

2.动态函数指针 

在学习这个知识点的时候,我遇到的坑,非常感谢这位大佬给我指点迷津:

动态函数指针free报错_编程语言-CSDN问答icon-default.png?t=N7T8https://ask.csdn.net/questions/8061857?spm=1001.2014.3001.5505

  • micthis大佬写的代码
#include <iostream>
using namespace std;
#include <memory>
#include <stdlib.h>
int add(int a, int b) {
    return a + b;
}
/*
    动态函数指针是指在运行时根据需要动态分配和修改的函数指针
    它可以在程序运行时根据需要指向不同的函数,从而实现更加灵活
    和动态的函数调用
    在c++中,可以使用动态内存分配函数(如malloc或new)来创建
    动态函数指针
*/
int test01() {
    // 创建一个指向函数的指针
    int(**pFunc)(int, int);
    // 使用malloc动态分配内存
    int size = sizeof(int(*)(int, int));
    pFunc = (int(**)(int, int))malloc(size);
    // 将函数指针指向 add函数
    *pFunc = add;
    // 调用函数
    int result = (*pFunc)(2, 3);
    cout << result << endl; // 输出 5
    // 释放内存
    free(pFunc);
    return 0;
}
int main() {
    test01();
    return 0;
}

打印结果: 

PS D:\Work\c++> ./bin/app
5
PS D:\Work\c++>

3.异步编程

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>

// A的实现,一般会隐藏
typedef void (*CallbackPtr)(int);// 函数指针定义

typedef struct dataCB{
    int data;
    CallbackPtr callback;
}dataCB;


// 创建实例
dataCB dataCBInstance = {0, NULL};

void* callback_thread(void* arg) { // 此处用的是一个线程
    // 循环改变p->a的值为 0 1 2 3 4 5 6 7 8 9,每个3s改变一次
    dataCB* p = (dataCB*)arg;
    while (1) {
        sleep(3);// 延时3s执行callback函数
        p->callback(p->data);// 函数指针执行函数,这个函数来自于应用层B
        p->data = (p->data + 1) % 10;
    }
}

void startup_app_A() {
    // 创建线程
    pthread_t tid;
    pthread_create(&tid, NULL, callback_thread, (void*)&dataCBInstance);   
}

// 给B的接口,接收注册函数
extern void SetCallBackFun(CallbackPtr cb) {
    printf("SetCallBackFun print! \n");
    dataCBInstance.callback = cb;
}

// //-----------------------应用者B-------------------------------
void recieve(int data)       // 应用者增加的函数,此函数会在A中被执行
{
    //do something
    printf("B得到A的数据 = %d\n",data);
}


int main(void) {
    // 启动A
    startup_app_A();
    SetCallBackFun(recieve);
    // 主函数
    while (1) {
        // std::cout << "main function" << std::endl;
        printf("main function\n");
        sleep(2);
    }
    return 0;
}
PS D:\Work\c++> ./bin/app
SetCallBackFun print!
main function
main function
B得到A的数据 = 0
main function
B得到A的数据 = 1
main function
main function
B得到A的数据 = 2
main function
B得到A的数据 = 3
main function
main function
B得到A的数据 = 4
main function
B得到A的数据 = 5
main function
main function
B得到A的数据 = 6
main function
B得到A的数据 = 7
main function
main function
B得到A的数据 = 8
main function
B得到A的数据 = 9
main function
main function
B得到A的数据 = 0
main function
B得到A的数据 = 1
main function
main function
B得到A的数据 = 2
main function
B得到A的数据 = 3
main function
main function
B得到A的数据 = 4
main function
B得到A的数据 = 5
main function
main function
B得到A的数据 = 6
main function
B得到A的数据 = 7
main function
main function
B得到A的数据 = 8
main function
B得到A的数据 = 9
main function
main function
B得到A的数据 = 0
main function

参考文章:C/C++面向对象(OOP)编程-回调函数详解(回调函数、C/C++异步回调、函数指针)-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/m0_47324800/article/details/135315345

二、C++回调函数

1.动态函数指针

#include <iostream>
using namespace std;
#include <memory>
#include <stdlib.h>
int add(int a, int b) {
    return a + b;
}
/*
    动态函数指针是指在运行时根据需要动态分配和修改的函数指针
    它可以在程序运行时根据需要指向不同的函数,从而实现更加灵活
    和动态的函数调用
    在c++中,可以使用动态内存分配函数(如malloc或new)来创建
    动态函数指针
*/
typedef int(*handleFunc)(int,int);
int test01() {
    // 创建一个指向函数的指针
    int(**pFunc)(int, int);
    pFunc = new handleFunc;
    // 将函数指针指向 add函数
    *pFunc = add;
    // 调用函数
    int result = (*pFunc)(2, 3);
    cout << result << endl; // 输出 5
    // 释放内存
    delete pFunc;
    pFunc = nullptr;
    return 0;
}
int main() {
    test01();
    return 0;
}

 2.简单回调

#include <iostream>
#include <functional>

// 定义一个回调函数类型
typedef std::function<void(int)> Callback;

// 定义一个接受回调函数的函数
void process(int value,Callback callback) {
    std::cout<<"传入处理值: "<<value<<std::endl;
    callback(value); // 调用回调函数
}

// 定义一个回调函数
int add(int value) {
    value += 10;
    std::cout<<"传出结果值: "<<value<<std::endl;
    return value;
}

int main() {
    int value = 42;
    process(value,add); // 传递回调函数给process函数
    return 0;
}

执行结果:

PS D:\Work\c++> ./bin/app
传入处理值: 42
传出结果值: 52
PS D:\Work\c++> 

 

未完待续 ~

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

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

相关文章

数据结构 归并排序详解

1.基本思想 归并排序&#xff08;MERGE-SORT&#xff09;是建立在归并操作上的一种有效的排序算法,该算法是采用分治法&#xff08;Divide andConquer&#xff09;的一个非常典型的应用。 将已有序的子序列合并&#xff0c;得到完全有序的序列&#xff0c;即先使每个子序列有序…

HAL库配置片内FLASH读写

一、FLASH简介 不同型号的 STM32F40xx/41xx&#xff0c;其 FLASH 容量也有所不同&#xff0c;最小的只有 128K 字节&#xff0c;最大 的则达到了 1024K 字节。我们的探索者开发板选择的是 STM32F407ZGT6 的 FLASH 容量为 1024K 字节。 主存储器&#xff0c;存放代码和数据常数&…

关于ZYZ旋转和XYZ旋转

ZYZ旋转和XYZ旋转 概述1、XYZ旋转2、ZYZ旋转 概述 以下公式默认为右手坐标系&#xff1b;ZYZ通常可以避免死解情况&#xff0c;因此在六轴末端解算时常被用到&#xff1b;参考文章 1、XYZ旋转 XYZ旋转一般是绕固定轴旋转(外旋)&#xff0c;旋转矩阵的构成为&#xff1a;RzRy…

关于如何利用ChatGPT提高编程效率的

自从去年ChatGPT3.5推出以后&#xff0c;这一年时间在编程过程中我也在慢慢熟悉人工智能的使用&#xff0c;目前来看即使是免费的ChatGPT3.5对于编程效率的提升也是有很大帮助的&#xff0c;虽然在使用过程中确实出现了一些问题&#xff0c;本文记录下我的一些心得体会和用法。…

ubuntu安装docker及插件docker-compose(详细图文)

目录 一、摘要 二、说明 三、安装docker及compose 方式一&#xff1a;采用apt存储库安装 1.设置 Docker 的存储库 2.1安装最新Docker包及其常用插件docker-compose 2.2安装指定 Docker 包及其常用插件docker-compose &#xff08;1&#xff09;列出所有存储库中docker版…

Docker中配置MySql环境

目录 一、简单安装 1. 首先从Docker Hub中拉取镜像 2. 启动尝试创建MySQL容器&#xff0c;并设置挂载卷。 3. 查看mysql8这个容器是否启动成功 4. 如果已经成功启动&#xff0c;进入容器中简单测试 4.1 进入容器 4.2 登录mysql中 4.3 进行简单添加查找测试 二、主从复…

Linux实验记录:使用Apache的虚拟主机功能

前言&#xff1a; 本文是一篇关于Linux系统初学者的实验记录。 参考书籍&#xff1a;《Linux就该这么学》 实验环境&#xff1a; VmwareWorkStation 17——虚拟机软件 RedHatEnterpriseLinux[RHEL]8——红帽操作系统 正文&#xff1a; 目录 前言&#xff1a; 正文&…

行业报告 | 工业机器人发展研报

原创 | 文 BFT机器人 工业机器人是一种能够自动执行任务的机器装置&#xff0c;是靠自身动力和控制能力来实现各种功能的一种机器。在工业生产过程中&#xff0c;可以大幅提高生产效率和产品质量。 随着科技的不断进步&#xff0c;工业机器人已经成为现代制造业的重要组成部分…

【Unity3D小技巧】Unity3D中UI控制解决方案

推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享简书地址我的个人博客 大家好&#xff0c;我是佛系工程师☆恬静的小魔龙☆&#xff0c;不定时更新Unity开发技巧&#xff0c;觉得有用记得一键三连哦。 一、前言 在开发中总是会控制UI界面&#xff0c;如何优雅的控制UI界面是…

亚马逊精品广告推广怎么做?亚马逊怎么看精品广告推广?站斧浏览器

亚马逊精品广告推广怎么做? 对于想要在亚马逊平台上进行精品广告推广的商家来说&#xff0c;以下是一些常见的操作步骤和注意事项。 首先&#xff0c;商家需要在亚马逊广告平台注册并创建广告账户。亚马逊广告平台提供了专门的自助式广告管理工具&#xff0c;商家可以通过该…

数据结构-图的最小生成树

最小生成树介绍 最小生成树(Minimum Cost Spanning Tree)是代价最小的连通网的生成树&#xff0c;即该生成树上的边的权值和最小 最小生成树的性质&#xff1a; 必须使用且仅使用连通网中的n-1条边来联结网络中的n个顶点&#xff1b; 不能使用产生回路的边&#xff1b; 各…

linux vim 异常退出 异常处理 交换文件

交换文件 *.swp 格式 同时是隐藏的 如在vim一个文件&#xff0c; 在没有正常退出&#xff0c; 如直接断开连接 在次编辑这个文件 会出现下图的错误 解决方案&#xff1a; 直接删除这个交换文件即可 rm -fr .zen.txt.swp

css3 属性 backface-visibility 的实践应用

backface-visibility 是一个用于控制元素在面对屏幕不同方向时的可见性的CSS3特性。它有两个可能的值&#xff1a; visible&#xff1a;当元素不面向屏幕&#xff08;即背面朝向用户&#xff09;时&#xff0c;元素的内容是可以被看到的。hidden&#xff1a;当元素不面向屏幕…

【计算机网络】Socket的SO_REUSEADDR选项与TIME_WAIT

SO_REUSEADDR用于设置套接字的地址重用。当一个套接字关闭后&#xff0c;它的端口可能会在一段时间内处于TIME_WAIT状态&#xff0c;此时无法立即再次绑定相同的地址和端口。使用SO_REUSEADDR选项可以允许新的套接字立即绑定到相同的地址和端口&#xff0c;即使之前的套接字仍处…

如何使用Linux Archcraft结合内网穿透实现SSH远程连接

&#x1f4d1;前言 本文主要是使用Linux Archcraft结合内网穿透实现SSH远程连接的文章&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是青衿&#x1f947; ☁️博客首页&#xff1a;CSDN主页放风讲故事 &#…

过年了,程序员们,请多关照自己!休息是为了走得更远!

文章目录 过年了&#xff0c;程序员们&#xff0c;请多关照自己&#xff01;一、理解“卷”背后的代价二、休息是为了走得更远三、关注健康&#xff0c;远离“过劳”四、平衡工作与生活&#xff0c;追求全面发展 过年了&#xff0c;程序员们&#xff0c;请多关照自己&#xff0…

input框前面名字长短不一时,让上下input框对齐方法

没设置之前 设置之后&#xff1a; 代码如下&#xff1a; <style>div{width: 500px;}label {display: block; /* 设置 label 元素为块级元素 */text-align: right; /* 设置文本右对齐 */margin-bottom: 10px; /* 设置标签之间的间距 */} </style> </head><…

Aigtek射频功率放大器有哪些具体应用

射频功率放大器是一种用于增加射频信号功率的电子器件。它在众多领域中有着广泛的具体应用&#xff0c;下面安泰电子将详细介绍几个主要的应用领域。 无线通信&#xff1a;射频功率放大器在无线通信系统中扮演着重要的角色。在移动通信领域&#xff0c;如蜂窝网络和卫星通信系统…

Solidworks 与 MATLAB 联合仿真

本文主要讲解了“MATLAB与SolidWorks的联合仿真怎么实现”&#xff0c;文中的讲解内容简单清晰&#xff0c;易于学习与理解&#xff0c;下面请大家跟着小编的思路慢慢深入&#xff0c;一起来研究和学习“MATLAB与SolidWorks的联合仿真怎么实现”吧&#xff01; 下载插件。 1、…

linux免密登录的实现

ssh免密登录使用方便&#xff0c;关键没有了口令验证反倒规避了暴力破解或者被探测的风险。配置得当&#xff0c;使用ssh免密登录更加安全。在生产环境中应用和数据库服务器之间互相设置后使用方便&#xff0c;并且在第三方人员配置使用时不用告知对方密码。 第一步、ssh登录发…