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

浅探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.xdnf.cn/news/15720.html

相关文章:

  • macOS 字体管理全攻略:如何查看已安装字体及常见字体格式区
  • 建立框架思维
  • Python爬虫实战:Requests与Selenium详解
  • ESP8266服务器建立TCP连接失败AT+CIPSTART=“TCP“,“192.168.124.1“,8080 ERROR CLOSED
  • MacOS安装linux虚拟机
  • 6、docker network
  • 验证损失判断过拟合情况
  • 【LeetCode刷题指南】--数组串联,合并两个有序数组,删除有序数组中的重复项
  • MongoDB社区版安装(windows)
  • React Native打开相册选择图片或拍照 -- react-native-image-picker
  • 腾讯云服务上下载docker以及使用Rabbitmq的流程
  • C++进阶-AVL树(平衡二叉查找树)(难度较高)
  • 深入理解CSS定位:绝对定位的包含块机制
  • 破解本地数据库困局:DbGate+内网穿透如何实现远程管理自由
  • Agent的深度解析:从原理到实践
  • docker更换国内加速器-更换华为加速器2025-717亲测可用docker 拉取镜像出错
  • 大模型Agent应用开发实战:从框架选型到行业落地
  • 【WPF】WPF 自定义控件之依赖属性
  • Linux717 SWAP扩容;逻辑卷条带化
  • 时序数据库选型指南︰为什么IoTDB成为物联网场景首选?
  • 销采一体化 CRM 与 人工管理效率对比
  • Go语言时间控制:定时器技术详细指南
  • 3t车用手动卧式千斤顶设计含8张CAD图纸PDF图
  • git的cherry-pick
  • smolagents - agent迭代式解题过程示例
  • Ollama使用指南-更改默认安装路径和Model路径(安装到非C盘)
  • 【46】MFC入门到精通——MFC显示实时时间,获取系统当前时间GetCurrentTime()、获取本地时间GetLocalTime()
  • HTML 极简个人介绍卡片(侧重语义化标签和响应式布局)
  • HCIE - 云计算方向考什么?一文全解
  • LIN通信驱动代码开发注意事项