news 2026/4/16 12:05:38

什么是回调函数?为什么要先把函数地址保存起来,再去调用,不能条件满足后,直接调用原来的函数吗

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
什么是回调函数?为什么要先把函数地址保存起来,再去调用,不能条件满足后,直接调用原来的函数吗

驱动 / BSP / FPGA + PS 代码,**回调函数(callback)**在这里用得非常多。
我用一句话定义 → 直观类比 → 代码级解释 → 你现在这类工程里的真实用途四层来讲。


一句话定义(先抓本质)

回调函数 = “我先把函数地址告诉你,将来在某个事件发生时,你再反过来调用我。”

重点不在“函数”,而在“把控制权交出去、等对方来调用”


生活类比(非常重要)

普通函数(你主动调用)

你 → 打电话 → 餐厅

回调函数(你被动等通知)

你 → 留电话号码 → 餐厅 餐厅 → 菜好了 → 打电话给你

📌电话号码 = 函数指针
📌餐厅 = 框架 / 驱动 / 中断系统


C 语言里的本质(最核心)

1️⃣ 函数也是“地址”

voidmy_func(void){}

my_func本质是:

一个代码段的入口地址

2️⃣ 用“函数指针”保存这个地址

void(*callback)(void);callback=my_func;

现在:

callback 指向 my_func

3️⃣ 别人通过这个指针调用你

callback();// 实际执行 my_func()

📌你没主动调用,是“被调用”


标准回调示例(一步到位)

// 1. 定义回调类型typedefvoid(*event_cb_t)(int);// 2. 注册回调event_cb_tcb;voidregister_cb(event_cb_tf){cb=f;}// 3. 某个事件发生voidevent_happen(void){if(cb)cb(123);}// 4. 用户写的回调函数voidmy_callback(intv){printf("event value = %d\n",v);}intmain(){register_cb(my_callback);// 把“地址”交出去event_happen();// 框架反过来调你}

⚠️ 回调函数的本质特点(牢记)

特性说明
被动执行你不知道什么时候被调用
不能阻塞不能while(1)、不能长延时
不能假设上下文可能在中断 / 驱动 / 任务中
常配合状态机用于“事件触发”而不是“流程控制”

一、最直接的答案(先给结论)

因为“触发条件的代码”和“要执行的函数”往往不在同一个地方、甚至不在同一个模块、不同的人写的代码里。

所以:

  • 触发者不能、也不应该“写死”要调用哪个函数
  • 只能提供一个“接口”:
    👉谁想被调用,就把函数地址交出来

二、如果“直接调用”,会发生什么问题?

我们先假设你说的“直接调用”👇

❌ 写死调用(最简单但最糟)

if(dma_done){update_Carrier_DDS();}

看起来很简单,但有 4 个致命问题


❌ 问题 1:触发者“绑死”业务逻辑

DMA 驱动现在知道

  • GNSS
  • Carrier
  • DDS

📌驱动层不该知道这些

驱动只应该知道:
“DMA 完成了”


❌ 问题 2:无法复用

今天你要:

  • DMA 完成 → 更新 DDS

明天你要:

  • DMA 完成 → 发消息
  • DMA 完成 → 切 buffer
  • DMA 完成 → 啥也不做

❓ 那怎么办?

👉改 DMA 驱动源码?

这是灾难级设计。


❌ 问题 3:多个用户怎么办?

DMA 完成后: - 模块 A 要知道 - 模块 B 也要知道

如果写死:

dma_done(){funcA();funcB();funcC();}

📌 这已经是“代码坟场”了。


❌ 问题 4:函数可能根本还不存在

在你现在的工程里:

  • 驱动 / 框架
  • 业务逻辑(GNSS / BB)

👉 往往是不同阶段、不同人、甚至不同仓库

驱动写的时候:

update_Carrier_DDS() 还不存在

三、为什么“保存函数地址”能解决这些问题?

我们来看同一件事,用回调怎么做。


✅ 回调设计

驱动 / 框架(只关心事件)
staticvoid(*dma_done_cb)(void)=0;voiddma_register_done_cb(void(*cb)(void)){dma_done_cb=cb;// 只存地址}voiddma_irq_handler(void){if(dma_done_cb)dma_done_cb();// 不关心是谁}
业务代码(决定“做什么”)
dma_register_done_cb(update_Carrier_DDS);

核心变化在哪里?

角色知道什么不知道什么
DMA 驱动DMA 完成DDS / GNSS / 业务逻辑
GNSS 模块要更新 DDSDMA 细节
联系方式函数地址源码依赖

👉彻底解耦


四、为什么“先保存”,不能“等条件到了再传”?

因为条件发生时,你已经没机会“再传”了

典型场景 1:中断

DMA 完成 → 硬件拉中断 → CPU 立即跳中断入口

❓ 此时你去哪儿“再传函数”?

👉只能提前准备好


典型场景 2:硬件事件(PPS)

PPS 上升沿 → 硬件状态机 → 触发处理

📌事件发生是“被动”的


典型场景 3:异步事件

你不知道什么时候发生

👉只能提前登记


五、放到你现在这套 GNSS + FPGA 工程里

你这套系统是:

FPGA 产生事件 → AXI 状态变化 → PS 轮询 / 中断 → 更新 DDS / Code / Nav

如果不用回调,你就只能:

while(1){if(if_req)update_Carrier_DDS();if(code_req)update_Code_DDS();if(nav_req)update_Nav();}

📌 这就是你现在看到的“巨型 while(1)”

回调的意义是:

把 “if_req → update_Carrier_DDS”
从 while 里拆出去


六、一句话点破你这个问题的本质

“直接调用”假设了:触发者知道业务;
“回调”承认了:触发者不该知道业务。


七、再给你一个“工程级类比”(你一定懂)

AXI 寄存器设计

PL 不会写:

if (if_req) call_update_carrier_dds();

而是:

if_req <= 1;

PS 看到if_req自己决定干什么

📌回调 = 软件里的 AXI 状态位



版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/15 9:48:50

CallBackRef函数

CallBackRef 是什么&#xff1a;为什么回调里既要函数指针&#xff0c;也要一个 void* 上下文 在 Xilinx 驱动&#xff08;例如 XSpiPs&#xff09;里&#xff0c;经常能看到这样的接口&#xff1a; void XSpiPs_SetStatusHandler(XSpiPs *InstancePtr,void *CallBackRef,XSpiP…

作者头像 李华
网站建设 2026/4/11 1:47:07

Dify文档保存失败怎么办:5个实用技巧助你快速恢复工作流

第一章&#xff1a;Dify文档保存失败的常见现象与影响在使用 Dify 平台进行文档编辑与管理过程中&#xff0c;用户可能会频繁遭遇文档无法正常保存的问题。这类故障不仅影响开发效率&#xff0c;还可能导致关键数据丢失&#xff0c;进而对项目进度造成连锁反应。典型表现 点击“…

作者头像 李华
网站建设 2026/4/15 16:52:05

Obfuscar混淆工具:从零开始的完整配置指南

Obfuscar混淆工具&#xff1a;从零开始的完整配置指南 【免费下载链接】obfuscar Open source obfuscation tool for .NET assemblies 项目地址: https://gitcode.com/gh_mirrors/ob/obfuscar 想要保护你的.NET代码不被反编译&#xff1f;Obfuscar混淆工具就是你需要的终…

作者头像 李华
网站建设 2026/4/16 0:10:22

GLM-4.6V-Flash-WEB与无人机巡检系统的实时反馈机制

GLM-4.6V-Flash-WEB与无人机巡检系统的实时反馈机制 在电力线路的高山峻岭间&#xff0c;在风力发电机的巨大叶片下&#xff0c;在广袤无垠的光伏阵列之上&#xff0c;传统的人工巡检早已难以为继。运维人员翻山越岭、攀爬高塔&#xff0c;不仅效率低、风险高&#xff0c;还难以…

作者头像 李华
网站建设 2026/4/16 11:03:56

Estedad字体:让你的多语言设计更出彩

Estedad字体&#xff1a;让你的多语言设计更出彩 【免费下载链接】Estedad Sans Serif Arabic-Latin text typeface 项目地址: https://gitcode.com/gh_mirrors/es/Estedad 你是否曾经在设计多语言项目时&#xff0c;为找不到合适的字体而烦恼&#xff1f;Estedad字体可…

作者头像 李华
网站建设 2026/4/16 12:01:56

BiliTools智能视频总结:高效获取B站知识精华的必备工具

BiliTools智能视频总结&#xff1a;高效获取B站知识精华的必备工具 【免费下载链接】BiliTools A cross-platform bilibili toolbox. 跨平台哔哩哔哩工具箱&#xff0c;支持视频、音乐、番剧、课程下载……持续更新 项目地址: https://gitcode.com/GitHub_Trending/bilit/Bil…

作者头像 李华