【C/C 】浅谈C/C 中函数指针与回调函数

01、函数指针

1.1、函数指针定义

一个函数总是占用一段连续的内存区域,函数名在表达式中有时也会被转换为该函数所在内存区域的首地址,这和数组名非常类似。我们可以把函数的这个首地址(或称入口地址)赋予一个指针变量,使指针变量指向函数所在的内存区域,然后通过指针变量就可以找到并调用该函数。这种指针就是函数指针。

简言之:函数指针其实就是一个指针变量,代表着一段内存。

1.2、函数指针的定义形式

returnType (*pointerName)(param list);

returnType 为函数返回值类型,pointerName 为指针名称,param list 为函数参数列表。参数列表中可以同时给出参数的类型和名称,也可以只给出参数的类型,省略参数的名称,这一点和函数原型非常类似。

返回类型(*函数名)(参数表)

例如下面两种写法都是正确的。

「写法一:」

void (*F_TYPE)(int nParam,char strName); //带参数变量名

「写法二:」

void (*F_TYPE)(int,char); //不带参数变量名

注意事项:注意( )的优先级高于*,第一个括号不能省略,如果写作returnType pointerName(param list);就成了函数原型,它表明函数的返回值类型为returnType*

1.3、函数指针与typedef

想必大家都能看出来,函数指针的定义是很长一段的,如果每次是用都要写这么长一段,额,大可不必,因为,typedef能够解决这个问题。

typedef:程序中的作用一般是取别名,例如下面这个例子,我们把函数指针换个名字。

typedef 返回类型(*新类型)(参数表)

//1.默认原始写法:
void callbackint(int a, int b, int (*pMsg)(int a,int b)); 
//2.typedef优化后:
typedef void (*PSM)(int a, int b);
void callbackint(int a, int b, PSM p);

这样做的好处是,以后只要需要使用int (*pMsg)(int a, int b)的地方我们都能使用PSM p这种方式来替换他。

typedef是C语言基础,这里不浪费时间在关键字上面,感兴趣的可以自行了解一下。

02、回调函数

2.1、回调函数定义

百度给的解释是:

回调函数就是一个被作为参数传递的函数。在C语言中,回调函数只能使用函数指针实现,在C 、Python、ECMAscript等更现代的编程语言中还可以使用仿函数或匿名函数。回调函数的使用可以大大提升编程的效率,这使得它在现代编程中被非常多地使用。同时,有一些需求必须要使用回调函数来实现。最著名的回调函数调用有C/C 标准库stdlib.h/cstdlib中的快速排序函数qsort和二分查找函数bsearch中都会要求的一个与strcmp类似的参数,用于设置数据的比较方法。

关于名词仿函数,请参考STL源码剖析中的算法一块儿,会有非常细致的解释。

我自己的理解就是:通过参数将函数地址传入,在多线程中,如果主线程在执行此函数时,通过参数中的函数地址,相当于异步执行了另外一个函数,另外一个函数也就是我们所称的回调函数,回调函数多用于socket、http等协议中的消息交互处理,回调函数的本质就是C/C 中的函数指针,如上所述。

2.2、回调函数的使用场景

著名的 lone wolf 曾经解释过这个问题:

其实回调就是一种利用函数指针进行函数调用的过程. 为什么要用回调呢?比如我要写一个子模块给你用, 来接收远程socket发来的命令.当我接收到命令后, 需要调用你的主模块的函数, 来进行相应的处理.但是我不知道你要用哪个函数来处理这个命令, 我也不知道你的主模块是什么.cpp或者.h, 或者说, 我根本不用关心你在主模块里怎么处理它, 也不应该关心用什么函数处理它…… 怎么办? 使用回调!

什么是回调函数?

回调函数是应用程序提供给Windows系统DLL或其它DLL调用的函数,一般用于截获消息、获取系统信息或处理异步事件。应用程序把回调函数的地址指针告诉DLL,而DLL在适当的时候会调用该函数。回调函数必须遵守事先规定好的参数格式和传递方式,否则DLL一调用它就会引起程序或系统的崩溃。通常情况下,回调函数采用标准WindowsAPI的调用方式,即__stdcall,当然,DLL编制者可以自己定义调用方式,但客户程序也必须遵守相同的规定。在__stdcall方式下,函数的参数按从右到左的顺序压入堆栈,除了明确指明是指针或引用外,参数都按值传递,函数返回之前自己负责把参数从堆栈中弹出。理解回调函数!

在很多第三方库中,比如libcurl中:

CURL_EXTERN curl_easy_setopt(CURL* curl,CURLoption option, ...);

就是用了回调函数,通过设置一个函数地址,当我们将内容发送到http请求页面之后,页面会通过字节流返回一个stringstream类型数据,里面就是我们请求服务器之后的返回结果,在一些频繁请求中,你不可能做到每一个都要程序停下来处理,这个时候,就可以使用回调函数来处理,异步通讯。

多线程中:主线程收发数据、子线程处理响应数据。大致都是一个意思。

03、实例重释

我这里分文件举一个简单的例子阐述刚才上面说到的内容。可能内容不够精炼,大佬请随意,初学者建议看一下,很好理解。

功能:创建一个函数,传递两个int类型参数,通过回调函数返回其两个int类型参数的计算结果。

CallBack.h内容如下:

#ifndef _CALLBACK_H
#define _CALLBACK_H//使用typedef进行简化代码,按部就班的写肯定没问题
typedef int (*PMSGMessage)(int a, int b);//回调函数
int callbackInt(int a, int b, PMSGMessage p); #endif

CallBack.cpp内容如下:

#include 
#include "CallBack.h"using namespace std;int callbackInt(int a ,int b, PMSGMessage p)
{//回调函数实现retrun p(a,b)
}

test.cpp函数内容如下:

#include 
#include "CallBack.h"
using namespace std;int Multiplication(int a, int b)
{//参数检查(避免出现0)if( a == 0 || b == 0){cout << "其中有参数为0,结果应避免为0" << endl;return 0;}return a * b;
}int main()
{int n = 6;int m = 11;int bRet = callbackInt(n,m,add);//如果我们用了类,就是函数等都是成员函数,我们这里要带上域操作符(" :: ")cout << "回调函数执行的结果是:" << bRet << endl; system("pause");return 0;
}

小结:回调函数的简单应用大概就是这么多,如果有机会,建议多用点开源库,那里面很多地方都是用了回调函数机制,而且都是比此例子高级一点的用法,但是基本思想都一样,不要因为用法高级一点就害怕了,自己写两个例子之后,想必对于回调会有更深的理解。

来源:

https://blog.csdn.net/m0_43458204/article/details/116715045

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

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

相关文章

jvm 错误_JVM因“ OutOfMemory”错误而关闭-我该怎么办?

jvm 错误看起来似乎很神奇&#xff0c;但是在有关JVM设置的搜索请求结果中经常显示“来自深度”的特定呼声。 您可能会遇到“我记得那个选项&#xff0c;但如何启用它”的问题&#xff0c;而有时&#xff08;主要是半年一次&#xff09;管理服务器或调整虚拟设备&#xff0c;而…

天线3db波束宽度_浅谈 Wi-Fi 天线(2)

在上一期内容中&#xff0c;我们为大家解读了增益(gain)、天线方向图(Antennae Directional Pattern)两个天线技术参数&#xff0c;本期我们来谈谈波束宽度(lobe width)。另一个常见的天线参数是“波束宽度”(又名&#xff1a;波瓣宽度)&#xff0c;英文是 lobe width 或 beam …

C语言实例:3个数从小到大排序

需求任意输入3个整数&#xff0c;对这3个整数由小到大进行排序&#xff0c;并将排序后的结果输出。源码// // author: 冲哥 // date: 2021/5/7 13:37 // description: 实现对这3个整数由小到大进行排序 #include int main() {int num1, num2, num3, temp;printf("请输入3个…

oracle u01清理,Oracleの/u01/11g/diag/rdbms/orcl/orcl/incident 的清理

https://docs.oracle.com/cd/E11882_01/server.112/e25494/diag.htm#ADMIN11007每当一个错误发生的时候&#xff0c;oracle会创建一个incident&#xff0c;并且分配一个INCIDENT_ID号&#xff0c;同时在ADR HOME的INCIDENT目录中创建相应的INCIDENT 目录&#xff0c;每个错误号…

jar 、war、ear_在命令行上操作JAR,WAR和EAR

jar 、war、ear尽管Java IDE和许多图形工具使查看和操作Java归档文件&#xff08;JAR&#xff0c;WAR和EAR&#xff09;文件的内容比以往更加容易&#xff0c;但有时我还是更喜欢使用命令行jar命令来完成这些任务。 当我必须重复做某事或作为脚本的一部分来做时&#xff0c;尤其…

C语言 | 读写文件

C语言怎样向文件读写字符fgetc函数调用形式&#xff1a;fgetc&#xff08;fp&#xff09; 功能&#xff1a;从fp指向的文件读入一个字符。 返回值&#xff1a;读成功&#xff0c;带回所读的字符&#xff0c;失败则返回文件结束标志EOF&#xff08;即-1&#xff09;。fputc函数调…

哨兵系列卫星_空客“哥白尼哨兵-1C”卫星雷达天线首次展开双翼

【民航事儿】2020年8月11日&#xff0c;腓特烈港&#xff1a;通过模拟零重力环境并固定在特殊装置上&#xff0c;哥白尼哨兵-1C卫星的12.3米宽、860公斤重的合成孔径雷达(SAR)的雷达天线&#xff0c;首次成功的在位于德国腓特烈港的空中客车综合技术中心展开双翼。作为哨兵-1系…

oracle vm 环境支持,使用 Oracle VM 模板快速部署 Oracle RAC 环境

6. 实时监控部署状态日志[rootracnode1 racovm]# cat /tmp/progress-racovm.out2014-04-16 03:02:27:[buildcluster:Start:racnode1] Building 11gR2 RAC Cluster2014-04-16 03:02:27:[setsshroot:Start:racnode1] SSH Setup for the root user…2014-04-16 03:02:39:[setsshro…

C语言中return、break用法和区别

1returnreturn&#xff1a;跳出当前正在执行函数。使用方法&#xff1a;return &#xff08;表达式&#xff09;;其中&#xff0c;&#xff08;表达式&#xff09;是可以省略的。 1.有返回类型return通常都是带有返回类型的&#xff0c;比如返回int型变量&#xff1a;int Fun(v…

兴趣点推荐代码_如何解读霍兰德职业兴趣测评结果?

霍兰德职业兴趣测评不难&#xff0c;难的是如何解读测评结果&#xff0c;这才是生涯规划测评中最重要的部分。今天我们就来说说霍兰德职业兴趣测评的结果应该如何解读。兴趣测评的结果是六种类型得分最高的三个代码依次排列组合而成&#xff0c;所以基本上就是R-实用型、I-研究…

linux mint 18支持安卓编译,Linux mint 18版本开启SSH服务

linux mint 18版本默认是没有安装ssh server的需要手动安装安装ssh server&#xff1a;此命令需要联网&#xff0c;会自动下载安装安装之后看是否开始了ssh&#xff0c;看到ssh-agent 和sshd 说明ssh server 已经启动了如果没看到ssh server 需要手动启动需要/etc/init.d/ssh s…

jcg q8 固件_JCG学院开设了Java设计模式课程!

jcg q8 固件自从我们推出JCG学院以来&#xff0c;已经有一段时间了。JCG学院是一个基于付费内容的高级订阅网站&#xff0c;提供有关最新&#xff0c;最先进技术的一系列课程&#xff0c;从RedSQL数据库&#xff08;如Redis和CouchDB&#xff09;到Android移动开发。 当然&…

C语言520心形表白,初学者福利!!

C语言实现打印出心形&#xff0c;初学者的表白神器。解题思路&#xff1a;这道例题我分了4部分&#xff0c;前3行一部分&#xff0c;4-6行一部分&#xff0c;7-13行一部分&#xff0c;最后一行一部分&#xff0c;读者请仔细阅读注释&#xff0c;小林写的很详细了。前三行输出&a…

kali linux 2019教程,[教程]KALI LINUX 2.0 2019 更新国内源

2019年最新版本KALI 为 KALI 2019.1 下载地址:https://www.kali.org/downloads/有的新入门的朋友可能会问&#xff0c;为什么每次都无法手动更新 例如:Update命令的执行失败&#xff1f;其实系统是没有问题的&#xff0c;因为KALI自带的更新源是国外的。因国内延迟高&#xff0…

C | 构成和编码规范

C 的构成1.一个C 程序可以由一个程序单位或多个程序单位构成,每个程序单位为一个文件,编译过程中会对每个文件进行编译。2.每个程序文件包括&#xff1a;预处理命令、全局声明、函数&#xff0c;其中预处理命令就是程序开头的那行&#xff1b;全局声明则是在函数外进行的声明&a…

涡轮流量计说明书_实际应用中超声波流量计与电磁流量计哪个更好用

流量仪表是水务、石化等行业的重要仪器之一&#xff0c;可以用计量的眼睛来比喻。对于水务水利行业&#xff0c;更是具有特殊的意义。比如供水行业中的药剂的添加&#xff0c;如果相关的计量仪表精度不高&#xff0c;将直接影响到水质的优差&#xff0c;甚至会影响到用户人群的…

C语言数据类型转换(自动类型转换 强制类型转换)

数据类型转换就是将数据&#xff08;变量、数值、表达式的结果等&#xff09;从一种类型转换为另一种类型。自动类型转换自动类型转换就是编译器默默地、隐式地、偷偷地进行的数据类型转换&#xff0c;这种转换不需要程序员干预&#xff0c;会自动发生。1) 将一种类型的数据赋值…

C 为什么非要引入那几种类型转换?

为什么要引入这几种类型转换&#xff0c;它与C语言中的强制类型转换有什么区别&#xff1f;这四种类型转换分别应用在什么场景&#xff1f;C 为什么要引入这几种强制类型转换&#xff1f;我们都知道C 完全兼容C语言&#xff0c;C语言的转换方式很简单&#xff0c;可以在任意类型…

C语言笔试两题,有坑

题目一最近遇到的一个华为笔试题题目&#xff1a;对字符串中的所有单词进行倒排。说明&#xff1a;1、构成单词的字符只有26个大写或小写英文字母&#xff1b;2、非构成单词的字符均视为单词间隔符&#xff1b;3、要求倒排后的单词间隔符以一个空格表示&#xff1b;如果原字符串…

嵌入式linux文件系统启动,嵌入式Linux之文件系统启动分析【原创】

this.p{ m:2,b:2,loftPermalink:,id:fks_094068082086089066084084095095080087080066082082083075,blogTitle:嵌入式Linux之文件系统启动分析【原创】,blogAbstract:author&#xff1a;张继飞写在前面&#xff0c;这一切必须是在Linux内核挂载文件系统后。在Linux内核中找到/i…