news 2026/8/4 13:51: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/7/29 21:04:37

Zotero PDF2zh插件:英文文献高效阅读的终极解决方案

Zotero PDF2zh插件&#xff1a;英文文献高效阅读的终极解决方案 【免费下载链接】zotero-pdf2zh PDF2zh for Zotero | Zotero PDF中文翻译插件 项目地址: https://gitcode.com/gh_mirrors/zo/zotero-pdf2zh 还在为阅读英文文献而头疼吗&#xff1f;每天花费大量时间在词…

作者头像 李华
网站建设 2026/8/3 2:02:10

Sigma文件管理器终极指南:免费开源工具打造高效数字工作空间

在日常使用电脑时&#xff0c;你是否曾为杂乱无章的文件管理而烦恼&#xff1f;传统文件管理器功能单一、界面陈旧&#xff0c;难以满足现代用户对高效管理的需求。Sigma文件管理器作为一款免费开源的跨平台工具&#xff0c;正在重新定义现代文件管理的标准。无论你是Windows还…

作者头像 李华
网站建设 2026/7/30 2:08:48

Obfuscar混淆工具完整使用指南

Obfuscar混淆工具完整使用指南 【免费下载链接】obfuscar Open source obfuscation tool for .NET assemblies 项目地址: https://gitcode.com/gh_mirrors/ob/obfuscar Obfuscar是一个开源的.NET程序集混淆工具&#xff0c;通过重命名元数据来保护.NET应用程序中的敏感信…

作者头像 李华
网站建设 2026/7/30 0:42:36

ST7789显示屏终极指南:MicroPython快速上手全攻略

还在为嵌入式项目的显示界面发愁吗&#xff1f;今天我要向你推荐一个改变游戏规则的解决方案——基于MicroPython的ST7789显示屏驱动库。无论你是刚接触嵌入式开发的新手&#xff0c;还是正在寻找更高效显示方案的工程师&#xff0c;这个项目都能让你眼前一亮&#xff01; 【免…

作者头像 李华
网站建设 2026/8/2 2:24:54

手机玩游戏总卡顿?关闭这2个设置,流畅度提升一倍

很多人都有过这样的体验&#xff1a;手机玩游戏时突然掉帧、操作延迟&#xff0c;明明不是老旧机型&#xff0c;却总被卡顿影响体验。其实不用急着换设备&#xff0c;关闭两个默认开启的 “性能消耗项”&#xff0c;就能让游戏流畅度大幅提升。一、关闭后台应用刷新&#xff0c…

作者头像 李华
网站建设 2026/8/1 2:31:00

如何快速修复和编辑Unreal Engine游戏存档:终极免费工具指南

如何快速修复和编辑Unreal Engine游戏存档&#xff1a;终极免费工具指南 【免费下载链接】uesave-rs 项目地址: https://gitcode.com/gh_mirrors/ue/uesave-rs 还在为游戏存档损坏而烦恼吗&#xff1f;想备份珍贵游戏进度却不知从何下手&#xff1f;ue save-rs开源工具…

作者头像 李华