当前位置: 首页 > news >正文

浅探C语言的回调函数(Callback Function)

目录

前言

解析回调函数组成

        1.没有参数传递的回调函数

        2.有参数传递的回调函数 

使用

结语

 


前言

C语言里面有回调函数的用法,只要将函数的指针传入,对应的函数即可运行。这里我也贴一下其它解释:

回调函数本质是 "函数指针的参数化",通过将行为抽象为函数指针参数,实现动态控制流程。这种机制是C语言实现事件驱动、异步操作和通用算法的基石,广泛应用于系统编程、库设计和嵌入式开发中。


 

典型使用场景:

  1. 事件处理(如GUI库中的按钮点击)

  2. 异步操作(如I/O操作完成后的通知)

  3. 算法通用化(如排序函数qsort()中的自定义比较逻辑)

  4. 库函数设计(允许用户注入自定义行为)

本文我们研究研究这个回调函数。

解析回调函数组成

这里我提供两个比较通用的回调函数,一个是没有参数的回调,一个是有参数的回调。

//无参数的回调函数
void callback(void *fun)
{((void *(*)())(fun))();
}//有参数的回调函数
void callback(void *fun, void *arg)
{((void *(*)(void *))(fun))(arg);
}

我们主要研究函数里面的那两个表达式,这才是回调函数的精髓。 

1.没有参数传递的回调函数

((void *(*)())(fun))();

这里其实有一个强制转换的过程

(void *(*)())

没错,括号里面其实是一个强制转换,转换为返回值为void *类型,(*)表明这里对应位置是一个指针,()表示没有参数。

然后在函数中对应

(fun)();

 最后就是对参数的处理,对转换完成的函数指针,表明没有参数。

((void *(*)())(fun))---->();

2.有参数传递的回调函数 

((void *(*)(void *))(fun))(arg);

同理,这里也有一个强制转换的过程

(void *(*)(void *))

强制转换为返回值为void *,(*)对应位置还是函数的指针,(void *)代表接收的参数是void *类型。

然后就是将转换之后的fun说明是那个参数arg 

(fun)(arg)

先转换,转换之后再赋上参数的值。

((void *(*)(void *))(fun))(arg);

使用

这里我贴的虽然是C++的代码,其实只是函数重载比较方便,改个函数名,一样能使用!

#include <iostream>
#include <unistd.h>
void callback(void *fun);
void callback(void *fun, void *arg);void *task(void *arg)
{long int num = (long int)arg;while (1){std::cout << "Hello!World!"<<"-->"<<num << std::endl;sleep(1);num++;}
}int main(int argc, char const *argv[])
{long int i = 0;callback((void *)task,(void *)i);return 0;
}void callback(void *fun)
{((void *(*)())(fun))();
}void callback(void *fun, void *arg)
{((void *(*)(void *))(fun))(arg);
}

结语

在C语言中,回调函数(Callback Function) 是一个通过函数指针调用的函数。其核心思想是将一个函数的地址作为参数传递给另一个函数(通常称为"调用函数"或"高阶函数"),当特定事件或条件发生时,调用函数会通过这个指针调用回调函数。

核心概念:

  1. 函数指针传递:回调函数的地址被作为参数传递给另一个函数。

  2. 异步执行:回调函数不会立即执行,而是在特定条件(如事件触发、任务完成)时被调用。

  3. 解耦与扩展性:调用函数无需知道回调函数的具体实现,只需定义接口,使代码更灵活。

http://www.lryc.cn/news/590923.html

相关文章:

  • 要实现在调用  driver.get()  后立即阻止页面自动跳转到 Azure 登录页,可通过以下几种方法实现:
  • AWS Lambda 最佳实践:构建高效无服务器应用的完整指南
  • Kubernetes ConfigMap 深度指南
  • 大模型Agent应用开发实战:从框架选型到行业落地
  • ros2 标定相机
  • 三轴云台之测距算法篇
  • 《C++初阶之STL》【auto关键字 + 范围for循环 + 迭代器】
  • 【Dv3Admin】菜单管理集成阿里巴巴自定义矢量图标库
  • 大型语言模型(LLM)在网络安全中最具商业价值的应用场景(Grok3 回答 DeepSearch模式)
  • Python包测试全攻略:从单元测试到持续集成
  • sqli-labs靶场通关笔记:第24关 二次注入
  • LiteSQL:让C++与数据库无缝对接的ORM利器
  • 河南萌新联赛2025第一场-河南工业大学
  • Redis面试相关问题总结
  • string + 栈 bitset 可达性统计(拓扑排序)
  • Redis深度解析:从缓存原理到高并发实战
  • Go语言高并发聊天室(三):性能优化与压力测试
  • 防火墙准入与拦截技术文档
  • Qt初阶开发:QMediaPlayer的介绍和使用
  • 杭州卓健信息科技有限公司 Java 面经
  • iOS App 电池消耗管理与优化 提升用户体验的完整指南
  • 暑期算法训练.3
  • 基于 Electron + Vue 3 的桌面小说写作软件架构设计
  • Python应用指南:使用PyKrige包实现ArcGIS的克里金插值法
  • Kubernetes (k8s)环境重启Pod方式总结
  • Perspective:一款开源的交互式分析和数据可视化组件
  • 独家|理想汽车放弃华为PBC模式,回归OKR理想汽车
  • 算法竞赛备赛——【图论】求最短路径——Dijkstra
  • 【软件开发】主流 AI 编码插件
  • 《Oracle SQL:使用 RTRIM 和 TO_CHAR 函数格式化数字并移除多余小数点》