1. 什么是回调函数?

回调函数,光听名字就比普通函数要高大上一些,那到底什么是回调函数呢?恕我读得书少,没有在那本书上看到关于回调函数的定义。我在百度上搜了一下,发现众说纷纭,有很大一部分都是使用类似这么一个场景来说明:A君去B君店里买东西,恰好缺货,A君留下号码给B君,有货时通知A君。感觉这个让人更容易想到的是异步操作,而不是回调。另外还有两句英文让我印象深刻:1) If you call me, I will call you back; 2) Don't call me, I will call you. 看起来好像很有道理,但是仔细一想,普通函数不也可以做到这两点吗?所以,我觉得这样的说法都不是很妥当,因为我觉得这些说法都没有把回调函数的特点表达出来,也就是都看不到和普通函数到底有什么差别。不过,百度百科的解析我觉得还算不错(虽然经常吐槽百度搜索...):回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。

下面先说说我的看法。我们可以先在字面上先做个分解,对于“回调函数”,中文其实可以理解为这么两种意思:1) 被回调的函数;2) 回头执行调用动作的函数。那这个回头调用又是什么鬼?

先来看看来自维基百科的对回调(Callback)的解析:In computer programming, a callback is any executable code that is passed as an argument to other code, which is expected to call back (execute) the argument at a given time. This execution may be immediate as in a synchronous callback, or it might happen at a later time as in an asynchronous callback. 也就是说,把一段可执行的代码像参数传递那样传给其他代码,而这段代码会在某个时刻被调用执行,这就叫做回调。如果代码立即被执行就称为同步回调,如果在之后晚点的某个时间再执行,则称之为异步回调。关于同步和异步,这里不作讨论,请查阅相关资料。

再来看看来自Stack Overflow某位大神简洁明了的表述:A "callback" is any function that is called by another function which takes the first function as a parameter。 也就是说,函数 F1 调用函数 F2 的时候,函数 F1 通过参数给 函数 F2 传递了另外一个函数 F3 的指针,在函数 F2 执行的过程中,函数F2 调用了函数 F3,这个动作就叫做回调(Callback),而先被当做指针传入、后面又被回调的函数 F3 就是回调函数。到此应该明白回调函数的定义了吧?

2. 为什么要使用回调函数?

很多朋友可能会想,为什么不像普通函数调用那样,在回调的地方直接写函数的名字呢?这样不也可以吗?为什么非得用回调函数呢?有这个想法很好,因为在网上看到解析回调函数的很多例子,其实完全可以用普通函数调用来实现的。要回答这个问题,我们先来了解一下回到函数的好处和作用,那就是解耦,对,就是这么简单的答案,就是因为这个特点,普通函数代替不了回调函数。所以,在我眼里,这才是回调函数最大的特点。来看看维基百科上面我觉得画得很好的一张图片。

Callback

下面以一段不完整的C语言代码来呈现上图的意思:

#include

#include // 包含Library Function所在读得Software library库的头文件

int Callback() // Callback Function

{

// TODO

return 0;

}

int main() // Main program

{

// TODO

Library(Callback);

// TODO

return 0;

}

乍一看,回调似乎只是函数间的调用,和普通函数调用没啥区别,但仔细一看,可以发现两者之间的一个关键的不同:在回调中,主程序把回调函数像参数一样传入库函数。这样一来,只要我们改变传进库函数的参数,就可以实现不同的功能,这样有没有觉得很灵活?并且丝毫不需要修改库函数的实现,这就是解耦。再仔细看看,主函数和回调函数是在同一层的,而库函数在另外一层,想一想,如果库函数对我们不可见,我们修改不了库函数的实现,也就是说不能通过修改库函数让库函数调用普通函数那样实现,那我们就只能通过传入不同的回调函数了,这也就是在日常工作中常见的情况。现在再把main()、Library()和Callback()函数套回前面 F1、F2和F3函数里面,是不是就更明白了?

明白了回调函数的特点,是不是也可以大概知道它应该在什么情况下使用了?没错,你可以在很多地方使用回调函数来代替普通的函数调用,但是在我看来,如果需要降低耦合度的时候,更应该使用回调函数。

3. 怎么使用回调函数?

知道了什么是回调函数,了解了回调函数的特点,那么应该怎么使用回调函数?下面来看一段简单的可以执行的同步回调函数代码。

#include

int Callback_1() //Callback Function 1

{

printf("Hello, this is Callback_1");return 0;

}int Callback_2() //Callback Function 2

{

printf("Hello, this is Callback_2");return 0;

}int Callback_3() //Callback Function 3

{

printf("Hello, this is Callback_3");return 0;

}int Handle(int (*Callback)())

{

printf("Entering Handle Function.");

Callback();

printf("Leaving Handle Function.");

}intmain()

{

printf("Entering Main Function.");

Handle(Callback_1);

Handle(Callback_2);

Handle(Callback_3);

printf("Leaving Main Function.");return 0;

}

运行结果:

Entering Main Function.

Entering Handle Function.

Hello,this isCallback_1

Leaving Handle Function.

Entering Handle Function.

Hello,this isCallback_2

Leaving Handle Function.

Entering Handle Function.

Hello,this isCallback_3

Leaving Handle Function.

Leaving Main Function.

可以看到,Handle()函数里面的参数是一个指针,在main()函数里调用Handle()函数的时候,给它传入了函数Callback_1()/Callback_2()/Callback_3()的函数名,这时候的函数名就是对应函数的指针,也就是说,回调函数其实就是函数指针的一种用法。现在再读一遍这句话:A "callback" is any function that is called by another function which takes the first function as a parameter,是不是就更明白了呢?

4. 怎么使用带参数的回调函数?

眼尖的朋友可能发现了,前面的例子里面回调函数是没有参数的,那么我们能不能回调那些带参数的函数呢?答案是肯定的。那么怎么调用呢?我们稍微修改一下上面的例子就可以了:

#include

int Callback_1(int x) //Callback Function 1

{

printf("Hello, this is Callback_1: x = %d", x);return 0;

}int Callback_2(int x) //Callback Function 2

{

printf("Hello, this is Callback_2: x = %d", x);return 0;

}int Callback_3(int x) //Callback Function 3

{

printf("Hello, this is Callback_3: x = %d", x);return 0;

}int Handle(int y, int (*Callback)(int))

{

printf("Entering Handle Function.");

Callback(y);

printf("Leaving Handle Function.");

}intmain()

{int a = 2;int b = 4;int c = 6;

printf("Entering Main Function.");

Handle(a, Callback_1);

Handle(b, Callback_2);

Handle(c, Callback_3);

printf("Leaving Main Function.");return 0;

}

运行结果:

Entering Main Function.

Entering Handle Function.

Hello,this is Callback_1: x = 2Leaving Handle Function.

Entering Handle Function.

Hello,this is Callback_2: x = 4Leaving Handle Function.

Entering Handle Function.

Hello,this is Callback_3: x = 6Leaving Handle Function.

Leaving Main Function.

可以看到,并不是直接把int Handle(int (*Callback)()) 改成 int Handle(int (*Callback)(int)) 就可以的,而是通过另外增加一个参数来保存回调函数的参数值,像这里 int Handle(int y, int (*Callback)(int)) 的参数 y。同理,可以使用多个参数的回调函数。

c语言timer linux 回调函数_C语言回调函数详解相关推荐

  1. linux getenv函数 get,linux之getenv putenv setenv和unsetenv详解

    1.getenv函数 头文件:#include 函数原型: char * getenv(const char* name); 函数说明:getenv()用来取得参数name环境变量的内容. 函数参数: ...

  2. 电大计算机C语言1253,1253《C语言程序设计》电大期末精彩试题及其问题详解

    1253<C语言程序设计>电大期末精彩试题及其问题详解 (34页) 本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦! 19.90 积分 实用文档&l ...

  3. Linux服务端开发——Linux中stat函数和stat命令使用详解

    这篇文章主要介绍了Linux中stat函数和stat命令使用详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧 stat函数和s ...

  4. Android 驱动(12)---Linux DTS(Device Tree Source)设备树详解

    Linux DTS(Device Tree Source)设备树详解 Linux DTS(Device Tree Source)设备树详解之一(背景基础知识篇) Linux DTS(Device Tr ...

  5. Linux文本处理必杀技之awk应用详解

    AWK是一个优良的文本处理工具,Linux及Unix环境中现有的功能最强大的数据处理引擎之一.这种编程及数据操作语言(其名称得自于它的创始人阿尔佛雷德·艾侯.彼得·温伯格和布莱恩·柯林汉姓氏的首个字母 ...

  6. Linux(centos)系统各个目录的作用详解

    转自:Linux(centos)系统各个目录的作用详解 现在公司的服务器使用CentOS系统,在网上找到了这篇介绍linux各个目录的文章,觉得十分不错,所以拿来存个档. 整理之后如下: 文件系统的类 ...

  7. 高通平台8953 Linux DTS(Device Tree Source)设备树详解之一(背景基础知识篇)

    本系列导航: 高通平台8953  Linux DTS(Device Tree Source)设备树详解之一(背景基础知识篇) 高通平台8953 Linux DTS(Device Tree Source ...

  8. 高通平台msm8953 Linux DTS(Device Tree Source)设备树详解之二(DTS设备树匹配过程)

    本系列导航: 高通平台8953  Linux DTS(Device Tree Source)设备树详解之一(背景基础知识篇) 高通平台8953 Linux DTS(Device Tree Source ...

  9. linux命令rz和sz,linux传输文件命令 rz 和 sz详解

    linux传输文件命令 rz 和 sz详解 一. 概述 rz,sz是Linux/Unix同Windows进行ZModem文件传输的命令行工具. 优点就是不用再开一个sftp工具登录上去上传下载文件. ...

  10. Linux打包(归档)和压缩详解

    Linux打包(归档)和压缩详解 一.打包(归档)和压缩(包含两者的区别) 二.Linux tar打包命令详解 2.1 tar命令做打包操作 2.2 tar命令做解打包操作 2.3 tar命令做打包压 ...

最新文章

  1. mock模拟的数据能增删改查吗_Mock.js模拟数据,脱离后端独立开发,实现增删改查功能...
  2. TinyXML2 的使用
  3. Android使用Intent实现拨打电话的动作
  4. clear ,refresh,free
  5. 前端学习(2669): vue3.0实战开始建立新项目
  6. linux 字符串 空,linux – bash空字符串/命令
  7. Java API —— IO流( FileInputStream FileOutputStream BufferedInputStream BufferedOutputStream )...
  8. 基础知识学习-数据结构篇
  9. 矩池云上TensorBoard/TensorBoardX配置说明
  10. 【音效处理】Reverb 混响算法简介
  11. 2017计算机二级c语言题库,2017年计算机C语言二级考试题库
  12. Docker 加速器
  13. EXCEL中关于角度的输入、输出及转换计算技巧
  14. 中国省市区json数据 三级联动
  15. nginx反向代理指定dns
  16. html 单元格被撑开_表格单元格td设置宽度无效始终有内部的内容撑开
  17. 旧电脑装什么系统最快_【老旧电脑装什么系统】老电脑装什么系统流畅_老旧电脑收藏...
  18. 卫生统计学v是什么意思_卫生统计学 名词解释
  19. 【Java】虚拟机JVM
  20. Hello React-姜威-专题视频课程

热门文章

  1. STM32-(33):低功耗模式与唤醒
  2. 一次运营配错活动的技术善后处理。
  3. java编写打字游戏_程序设计:简单字母打字游戏(JAVA编写)
  4. 基于Java+JSP+MySQL基于SSM的医院挂号就诊系统——计算机毕业设计
  5. 将本地项目代码上传到码云(Gitee)或GitHub
  6. Oxygen PDF Chemistry新功能
  7. Google Adwords新手快速入门教程
  8. wildfly(JBOSS)启动报错
  9. caspase家族的特点_caspase家族
  10. 28届计算机表演赛辽宁赛区,第十九届计算机表演赛辽宁赛区网络基础类竞赛结果.doc...