news 2026/4/16 12:58:23

CallBackRef函数

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
CallBackRef函数

CallBackRef 是什么:为什么回调里既要函数指针,也要一个 void* 上下文

在 Xilinx 驱动(例如XSpiPs)里,经常能看到这样的接口:

voidXSpiPs_SetStatusHandler(XSpiPs*InstancePtr,void*CallBackRef,XSpiPs_StatusHandler FunctionPtr);

很多人第一次看会困惑:既然已经传了回调函数FunctionPtr,为什么还需要一个CallBackRef

答案是:FunctionPtr决定“做什么”(代码),而CallBackRef决定“对谁做”(上下文数据)。
这两者解决的是两个不同维度的问题。


1. FunctionPtr:回调函数指针(代码地址)

回调函数指针告诉驱动:发生事件时调用哪段逻辑。例如 SPI 传输完成、模式错误等事件:

  • 传输完成 → 通知上层继续下一步
  • 错误发生 → 记录日志、重试或上报

驱动不可能替所有应用场景写死策略,所以用函数指针把“策略”交给用户。


2. CallBackRef:回调上下文指针(数据地址)

C 语言的函数指针不携带上下文,回调函数执行时,如果要访问某个对象或状态,就需要一个入口指针。CallBackRef就是这个入口。

它的特点:

  • 类型是void *:可以指向任何用户自定义的数据结构
  • 驱动不会解析它:仅在触发回调时原样传回
  • 在回调函数中由用户将其强制转换回真实类型

这相当于在 C 语言里用“函数指针 + void*”手工模拟面向对象里的“成员函数回调”或“闭包”。


3. 为什么不能只用一个回调函数?

如果只用FunctionPtr,回调函数怎么知道它在服务哪个对象?

例如一个工程里可能有多个 SPI 设备或多条总线:

  • SPI0 控制 AD9528
  • SPI1 控制 Flash 或 ADC
  • 或同一 SPI 上挂多个片选设备

如果只有函数指针,回调函数就必须依赖全局变量来区分“这是哪一个设备的完成事件”,工程规模一大就会:

  • 难以复用
  • 容易写错
  • 多实例难维护

有了CallBackRef,同一个回调函数可以用于多实例,只要传不同的上下文指针即可。


4. 最典型的用法:传一个“上下文结构体”

这是最推荐的方式:用结构体保存你在回调里需要用到的所有信息。

typedefstruct{volatileintdone;u32 last_event;u32 bytes;}spi_ctx_t;staticspi_ctx_tctx;staticvoidspi_status_cb(void*ref,u32 event,u32 bytes){spi_ctx_t*c=(spi_ctx_t*)ref;// CallBackRef -> 真实类型c->last_event=event;c->bytes=bytes;c->done=1;// 通知上层“传输完成/出错”}

注册回调:

XSpiPs_SetStatusHandler(&SpiInstance,&ctx,spi_status_cb);

这样,驱动内部发生事件时会调用:

InstancePtr->StatusHandler(InstancePtr->StatusRef,EventCode,Bytes);

其中StatusRef就是你注册的CallBackRef


5. 在 FreeRTOS 中更常见:把“句柄”作为 CallBackRef

在 RTOS 场景里,回调通常发生在 ISR 中。最常见做法是 ISR 回调里唤醒任务,典型手段包括:

  • SemaphoreHandle_t信号量
  • TaskHandle_t任务通知
  • QueueHandle_t队列事件

这些 handle 在 FreeRTOS 实现中往往就是“内核对象控制块的引用/指针”,正好可放进void*,因此可以直接作为CallBackRef传入。

例如用信号量等待 SPI 完成:

staticSemaphoreHandle_t spi_sem;staticvoidspi_status_cb(void*ref,u32 event,u32 bytes){SemaphoreHandle_t sem=(SemaphoreHandle_t)ref;BaseType_t hpw=pdFALSE;if(event==XST_SPI_TRANSFER_DONE){xSemaphoreGiveFromISR(sem,&hpw);portYIELD_FROM_ISR(hpw);}}voidinit_spi_cb(void){spi_sem=xSemaphoreCreateBinary();XSpiPs_SetStatusHandler(&SpiInstance,(void*)spi_sem,spi_status_cb);}

核心思想:
CallBackRef 指向“该通知谁”的目标,回调函数负责“怎么通知”。


6. CallBackRef 使用注意事项(工程必读)

6.1 生命周期必须足够长

回调是异步发生的(中断触发),所以不能把栈上局部变量地址作为 CallBackRef

voidbad(){intlocal;XSpiPs_SetStatusHandler(&SpiInstance,&local,cb);// 错:local 很快失效}

推荐使用:

  • 全局/static变量
  • 长生命周期对象(设备结构体、RTOS 句柄)
  • 动态分配(需要你自己管理释放时机)

6.2 回调里要做的事情尽量短

尤其在 ISR 回调中:

  • 只做置位、发信号量/通知、推队列等
  • 不做耗时打印、不做阻塞等待、不做长循环

6.3 类型转换要一致

驱动不会检查类型,你传什么,回调就按你传的类型去转换。类型不一致会导致严重错误。


7. 一句话总结

  • FunctionPtr(回调函数)=行为/策略(代码)
  • CallBackRef=上下文/对象引用(数据)

二者结合,让驱动在不依赖全局变量的前提下支持:

  • 多实例
  • 可复用回调
  • ISR/RTOS 同步
  • 应用层自定义处理策略
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/16 13:08:03

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Vue 3拖拽组件深度解析:从技术痛点到高效解决方案

Vue 3拖拽组件深度解析:从技术痛点到高效解决方案 【免费下载链接】vue.draggable.next Vue 3 compatible drag-and-drop component based on Sortable.js 项目地址: https://gitcode.com/gh_mirrors/vu/vue.draggable.next 开发困境与需求分析 在Vue 3项目…

作者头像 李华