编程嵌入式 C 开发人员

描述在 C 语言中如何实现和使用回调函数(callback functions)。在开发库或与 API 交互时,如何正确声明和使用这些函数?

用 Hintsage AI 助手通过面试

回答

回调函数(callbacks)是作为另一个函数的参数传递的函数地址。这使得实现事件处理程序、用户算法和插件成为可能。

回调函数的声明:

  1. 描述相应的函数指针类型:
typedef void (*callback_func_t)(int);
  1. 传递处理函数:
void process(callback_func_t cb) { // ... cb(42); // 调用回调 } void handler(int n) { printf("处理的数字: %d ", n); } int main() { process(handler); return 0; }

建议:

  • 遵循为指针类型使用明确的 typedef,代码更具可读性。
  • 确保回调函数的签名与预期相符。
  • 避免传递未初始化或已释放的局部函数。

陷阱问题

可以将签名不匹配的函数作为回调传递吗?

常见错误答案: “可以,如果声明明确的类型转换,C 会允许。”

正确答案: 尽管形式转换是可能的,但调用这样的函数将导致未定义行为——参数可能会传递错误的值,导致堆栈破坏。

危险示例:

typedef void (*cb_t)(int); void wrong_cb(double d) { printf("%f ", d); } void call(cb_t f) { f(123); } int main() { call((cb_t)wrong_cb); } // 危险:签名不匹配

由于对主题细节的不了解而导致的真实错误示例


故事

在一个嵌入式项目中,排序函数的 compare 函数接收了一个签名过于窄的函数指针。这导致了排序错误并因参数传递不当而导致的内存损坏。

故事

在图形引擎库中实现了基于回调的事件机制,但部分回调错误地引用了已释放动态库中的局部函数,这导致在遇到无效地址时发生崩溃。

故事

在开发跨平台系统时,作者错误地定义了回调函数的调用约定。这在一个操作系统上没有表现出来,但在调用来自 C 库的回调时在另一个操作系统上导致程序崩溃。