linux c 语言回调函数学习

动机

最近在看 IO多路复用,包括 select() poll () epoll() 的原理以及libevent, 对里面提及的回调机制 比较头大,特写此文用例记录学习笔记。

什么是回调函数

网上看到的最多的一句话便是:回调函数 就是 函数指针的一种用法,将回调函数指针作为另一个函数的参数

为什么要用回调函数

解耦
以下图为例:
在这里插入图片描述

  • 需求:我们知道排序算法有很多种,包括冒泡,选择,归并等等。现在我们想对某一个数组实现一个排序功能,需要对比不同算法的复杂度。
  • 针对该需求,上图可以抽象为如下代码:
#include<stdio.h>
#include<lib.h> // 包含Library函数的头文件int Callback() // Callback Function 用于定义实现不同的排序算法
{ 冒泡;选择;归并;...  return 0;
}
int main() // Main program
{%给定待排序的数组int a[3] ={2,1,3}; %% 库函数进行回调 (即:选择不同的排序算法)Library(Callback);return 0;
}
  1. 那么,可以看到 ,我们只需要向Library函数中 传入不同的参数,就可以实现不同的排序功能。
  2. 另外还可以看到,main和callback函数实现在一个文件,Library函数实现在另一个文件。现实工作中,这个Library函数怎么编写我们是看不见的,只能拿到Library函数提供给我们的一个接口,那我们只要给Library函数传入不同的回调函数,就可以实现不同的功能了

函数指针

前面提过,要把一个函数A作为另一个函数B的参数,很直接的一种方式就是向B 传入A的指针。
现对函数指针做个简单介绍:

函数指针也是一种指针,只是它指向的不是整型,字符型而是函数。在C中,每个函数在编译后都是存储在内存中,并且每个函数都有一个入口地址,根据这个地址,我们便可以访问并使用这个函数。函数指针就是通过指向这个函数的入口,从而调用这个函数。

函数指针的定义:

和其他指针的定义略有不同:

%整型指针
int *p = NULL;
%函数指针
/* 方法1 */
void (*p_func)(int, int, float) = NULL;
/* 方法2 */
typedef void (*tp_func)(int, int, float);
tp_func p_func = NULL;

上例定义了一个指向返回值为 void 类型

函数指针的赋值
void (*p_func)(int, int, float) = NULL;
p_func = &func1;
p_func = func2;

上面两种方法都是合法的,对于第二种方法,编译器会隐式地将 func_2 由 void ()(int, int, float) 类型转换成 void (*)(int, int, float) 类型,

使用函数指针调用函数
/* 方法1 */
int val1 = p_func(1,2,3.0);
/* 方法2 */
int val2 = (*p_func)(1,2,3.0);
将函数指针作为参数传给函数
/* func3 将函数指针 p_func 作为其形参 */
void func3(int a, int b, float c, void (*p_func)(int, int, float))
{(*p_func)(a, b, c);
}/* func4 调用函数func3 */
void func4()
{func3(1, 2, 3.0, func_1);/* 或者 func3(1, 2, 3.0, &func_1); */
}
函数指针作为函数返回类型
void (* func5(int, int, float ))(int, int)
{...
}
函数指针数组

如下代码定义了一个元素个数为5,类型是 void (*)(int, int, float) 的函数指针数组

/* 方法1 */
void (*func_array_1[5])(int, int, float);/* 方法2 */
typedef void (*p_func_array)(int, int, float);
p_func_array func_array_2[5];

回调函数简单例子

#include <stdio.h>
#include <stdlib.h>/***************************************** 加减乘除函数***************************************/
float ADD(float a, float b) 
{return a + b;
}float SUB(float a, float b) 
{return a - b;
}float MUL(float a, float b) 
{return a * b;
}float DIV(float a, float b) 
{return a / b;
}/***************************************** 函数指针结构体***************************************/
typedef struct _OP {float (*p_add)(float, float); float (*p_sub)(float, float); float (*p_mul)(float, float); float (*p_div)(float, float); 
} OP; /***************************************** 初始化函数指针***************************************/
void init_op(OP *op)
{op->p_add = ADD;op->p_sub = SUB;op->p_mul = &MUL;op->p_div = &DIV;
}/***************************************** 库函数***************************************/
float add_sub_mul_div(float a, float b, float (*op_func)(float, float))
{return (*op_func)(a, b);
}int main()
{OP *op = (OP *)malloc(sizeof(OP)); init_op(op);/* 调用回调函数 */ printf("ADD = %f, SUB = %f, MUL = %f, DIV = %f\n", add_sub_mul_div(1.3, 2.2, ADD), add_sub_mul_div(1.3, 2.2, SUB), add_sub_mul_div(1.3, 2.2, MUL), add_sub_mul_div(1.3, 2.2, DIV));free(op);
}

参考:

1
2:https://segmentfault.com/a/1190000008293902

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/60711.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Ceph PG(归置组)的状态说明

Ceph PG&#xff08;Placement Group&#xff09;的状态反映了Ceph集群中数据的健康状况和分布情况。以下是Ceph PG的一些常见状态&#xff1a; Creating&#xff1a;创建状态。在创建存储池时&#xff0c;会创建指定数量的归置组&#xff08;PG&#xff09;。Ceph在创建一或多…

ElegantRL:高效、稳定的深度强化学习开源框架

ElegantRL是一个专为大规模并行深度强化学习&#xff08;DRL&#xff09;设计的开源框架&#xff0c;由Yonv1943&#xff08;或AI4Finance-Foundation&#xff09;开发。以下是关于ElegantRL的详细介绍&#xff1a; 一、项目背景与特点 项目名称&#xff1a;ElegantRL&#xf…

游戏引擎学习第九天

视频参考:https://www.bilibili.com/video/BV1ouUPYAErK/ 修改之前的方波数据&#xff0c;改播放正弦波 下面主要讲关于浮点数 1. char&#xff08;字符类型&#xff09; 大小&#xff1a;1 字节&#xff08;8 位&#xff09;表示方式&#xff1a;char 存储的是一个字符的 A…

SRIO RapidIO 笔记

RapidIO 基础与底层包类型 1.RapidIO 是基于数据包交换的互联体系结构 类似 Mac 层使用以太网的计算机网络&#xff08;IEEE802.3&#xff09;&#xff1f; 首先 RapidIO 是一个互联协议&#xff08;类似计算机网络 IEEE802.3&#xff09;&#xff0c;包含硬件与软件的定义&…

python makedirs() 详解

在 Python 中&#xff0c;os.makedirs() 函数用于递归地创建目录。也就是说&#xff0c;它不仅会创建指定的目录&#xff0c;还会创建任何必要的父目录。这个函数在处理需要创建多级目录结构时非常有用。 1、语法 os.makedirs(name, mode0o777, exist_okFalse) 1.1、参数 n…

# Python IDE的介绍和选择 --- 《跟着小王学Python》

Python IDE的介绍和选择 — 《跟着小王学Python》 《跟着小王学Python》 是一套精心设计的Python学习教程&#xff0c;适合各个层次的学习者。本教程从基础语法入手&#xff0c;逐步深入到高级应用&#xff0c;以实例驱动的方式&#xff0c;帮助学习者逐步掌握Python的核心概念…

摄影:机位

机位 初步拆分机位高度平视机位优势特写、近景分不清。劣势 高机位低机位 初步拆分机位 我们可以将机位分为&#xff1a;高度、角度、距离三个方面。 高度-平视机位、高机位、低机位。 角度-正面、侧面、背面。 距离-取景范围-远、全、中、近、特 高度 平视机位 相机与相机…

Modern Effective C++:item 1 理解模板类型推导

通用引用&#xff08;万能引用&#xff09; 通用引用通常表示为 T&&&#xff0c;其中 T 是一个模板参数类型&#xff08;模板中的&&表示通用引用&#xff09;。&& 虽然通常表示一个右值引用&#xff0c;但当T由模板参数推导而来时&#xff0c;其既可以…

机器学习——期末复习 重点题归纳

第一题 问题描述 现有如下数据样本&#xff1a; 编号色泽敲声甜度好瓜1乌黑浊响高是2浅白沉闷低否3青绿清脆中是4浅白浊响低否 &#xff08;1&#xff09;根据上表&#xff0c;给出属于对应假设空间的3个不同假设。若某种算法的归纳偏好为“适应情形尽可能少”&#xff0c;…

柯桥生活英语口语学习“面坨了”英语怎么表达?

“面坨了”英语怎么表达&#xff1f; 要想搞清楚这个表达&#xff0c;首先&#xff0c;我们要搞明白“坨”是啥意思&#xff1f; 所谓“坨”就是指&#xff0c;面条在汤里泡太久&#xff0c;从而变涨&#xff0c;黏糊凝固在一起的状态。 有一个词汇&#xff0c;很适合用来表达这…

ZeroSSL HTTPS SSL证书ACMESSL申请3个月证书

目录 一、引言 二、准备工作 三、申请 SSL 证书 四、证书选型 五、ssl重要性 一、引言 目前免费 Lets Encrypt、ZeroSSL、BuyPass、Google Public CA SSL 证书&#xff0c;一般免费3-6个月。从申请难易程度分析&#xff0c;zerossl申请相对快速和简单&#xff0c;亲测速度非…

Java连接MySQL(测试build path功能)

Java连接MySQL&#xff08;测试build path功能&#xff09; 实验说明下载MySQL的驱动jar包连接测试的Java代码 实验说明 要测试该情况&#xff0c;需要先安装好MySQL的环境&#xff0c;其实也可以通过测试最后提示的输出来判断build path是否成功&#xff0c;因为如果不成功会直…

第四节-OSI-网络层

数据链路层&#xff1a;二层--MAC地址精确定位 Ethernet 2&#xff1a; 报头长度&#xff1a;18B 携带的参数&#xff1a;D MAC /S MAC/TYPE(标识上层协议)/FCS 802.3 报头长度&#xff1a;26B 携带的参数&#xff1a;D MAC/S MAC/LLC(标识上层协议)/SNAP&#xff08;标识…

Spring Boot 中 Druid 连接池与多数据源切换的方法

Spring Boot 中 Druid 连接池与多数据源切换的方法 在Spring Boot项目中&#xff0c;使用Druid连接池和进行多数据源切换是常见的需求&#xff0c;尤其是在需要读写分离、数据库分片等复杂场景下。本文将详细介绍如何在Spring Boot中配置Druid连接池并实现多数据源切换。 一、…

labview实现功能性全局变量

在日常的项目中&#xff0c;笔者最长使用的就是全局变量&#xff0c;这样用起来不仅省心省力&#xff0c;而且传值也很方便&#xff0c;没有什么阻碍&#xff0c;想要传什么数据一根线拉过去就可以了。后面才知道如果一直使用全局变量会导致读写卡死的状态&#xff0c;而且还有…

网络安全之SQLMAP _DNS注入配置方法

网上针对sqlmap进行dns注入的相关文章太少&#xff0c;只是简单介绍了下–dns-domain参数&#xff0c;相关的实战文章要么就模糊或者一笔带过&#xff0c;。然后参考网上的方法重新整理了一遍&#xff0c;简单理解。 需要准备的东西&#xff0c;sqlmap、windows盲注一个、两个…

web浏览器环境下使用window.open()打开PDF文件不是预览,而是下载文件?

如果你使用 window.open() 方法打开 PDF 文件&#xff0c;但浏览器不是预览而是下载文件&#xff0c;这可能是由于以下几个原因&#xff1a; 服务器配置&#xff1a;服务器可能将 PDF 文件配置为下载而不是预览。例如&#xff0c;服务器可能设置了 Content-Disposition 响应头…

pycharm快速更换虚拟环境

目录 1. 选择Conda 虚拟环境2. 创建环境3. 直接选择现有虚拟环境 1. 选择Conda 虚拟环境 2. 创建环境 3. 直接选择现有虚拟环境

联想“喜新厌旧”

科技新知 原创作者丨萧维 编辑丨蕨影 十月份&#xff0c;联想很忙。 先是2024联想科技创新大会15日在美国华盛顿州西雅图举行&#xff0c;联想大秀了一下自己在人工智能领域的创新产品、技术和解决方案&#xff0c;英特尔、AMD、英伟达三巨头更同时为其站台&#xff1b;后是与…

[白月黑羽]关于仿写类postman功能软件题目的解答

原题&#xff1a; 答&#xff1a; python文件如下 from PySide6.QtWidgets import QApplication, QMessageBox,QTableWidgetItem,QHeaderView,QWidget,QTableWidget from PySide6.QtCore import QEvent,QObject from PySide6.QtUiTools import QUiLoader import time import …