源地址:https://argcv.com/articles/2669.c

callback,函数的回调,从ANSI C开始,一直被广为使用。无论是windows API的所谓消息机制,动态链接库的调用,还是sqlite的命令,gcc下的pthread,qsort。callback都在其中起着难以替代的作用。

那么,callback为何如此受到亲睐呢?因为它可以以一个函数为参数,放到参数列表交给API,让API调用。比如有个文件夹下有一千万个文件,我们希望对每个文件进行一些处理,比如查看文件长度是否超过512字节。而遍历这个文件夹的程序是个API。如果不使用callback,API可能有两种办法,一种是申请一个超巨大的空间,然后把找到的所有文件名都放进去,然后返回这个空间(类似的还有把这组文件名写到文件中,一个意思),这样速度的确很快,而且简单方便,但问题是,一千万个文件,占用的空间是如此的庞大,空间复杂度为O(n),而我们只是要对每个文件进行一点小小的处理而已,实在是杀鸡焉用宰牛刀。另一个方法是搞个迭代器,每次只返回一个文件名,下次调用再返回下个。为了线程安全,每次传参都得来个指针之类的记录自己的进度。如果做的细心,也可以做的很快,也不占用空间。但问题是,只是个简单的遍历文件夹的API,这么折腾好累哦。而如果使用callback,事情就简单很多了。主程序调用API,把处理文件的函数用参数的方法传递给API,API每找到一个文件名,就调用这个函数,当场处理不用存储任何文件名。这样空间复杂度是O(1),而且方便有效,何乐而不为呢?

callback具体怎么实现的呢?我在本文中做一个小小的demo。
Demo的实现的功能是这样的:
bar.c调用foo.c的一个函数,请求给一个magic number。但foo.c的函数并不是直接返回,而是调用bar.c传递过来的函数use_magic_num,把magic number 作为参数使用进去。

首先,定义最后要被调用的函数use_magic_num如下:

1
2
3
4
5
6
void use_magic_num(int magic_num);
 
void use_magic_num(int magic_num)
{
    printf("bar.c : magic number is %d \n", magic_num);
}

也就是传进去一个参数,然后函数会打印出这个magic number。它被放置在bar.c下

然后foo.h中定义API get_magic_num的原型

1
void get_magic_num(void (*callback)(int magic));

它的参数列表和普通的有点区别,传入的是一个函数指针,这个函数必须是原型为有一个int类型为参数,返回为void。其他的就和普通的函数一样了。

对get_magic_num进行实现。

1
2
3
4
5
6
7
typedef void (*foo_run_magic)(int);
 
void get_magic_num(foo_run_magic foo)
{
    int magic = 9;
    foo(magic);
}

我么可以看到,在这儿,我做了点小花招,我typedef了这个函数指针,这样我们可以直接使用foo_run_magic来代替麻烦的各种括号的函数指针了。
然后调用 foo,其实就是调用传入的参数。在本工程中,也就是前面写的use_magic_num了。
虽然foo.c完全看不见use_magic_num,但完全不妨碍函数的使用。

最后定义bar.c的主程序

1
2
3
4
5
int main(int argc,char *argv[])
{
    get_magic_num(use_magic_num);
    return 0;
}

也就是调用foo并传入use_magic_num的函数了。

编译和执行结果大致是如下的样子:

1
2
3
4
5
6
7
[yu@argcv callback]$ make
gcc -c -Wall -std=c99 bar.c -o bar.o
gcc -c -Wall -std=c99 foo.c -o foo.o
gcc -Wall -std=c99 -o bar bar.o foo.o
[yu@argcv callback]$ ./bar
bar.c : magic number is 9
[yu@argcv callback]$

完整的工程请参考此处

callback用法简介的更多相关文章

  1. IOS NSInvocation用法简介

    IOS NSInvocation用法简介 2012-10-25 19:59 来源:博客园 作者:csj007523 字号:T|T [摘要]在 iOS中可以直接调用某个对象的消息方式有两种,其中一种就是 ...

  2. JodaTime用法简介

    JodaTime用法简介 Java的Date和Calendar用起来简直就是灾难,跟C#的DateTime差距太明显了,幸好有JodaTime 本文简单罗列JodaTime的用法 package co ...

  3. Apache自带压力测试工具ab用法简介

    ab命令原理 ab命令会创建很多的并发访问线程,模拟多个访问者同时对某一URL进行访问.它的测试目标是基于URL的,因此,既可以用来测试Apache的负载压力,也可以测试nginx.lighthttp ...

  4. Postman用法简介

    转自:http://blog.csdn.net/flowerspring/article/details/52774399 Postman用法简介 转载 2016年10月10日 09:04:10 10 ...

  5. MSSQL Sql加密函数 hashbytes 用法简介

    转自:http://www.maomao365.com/?p=4732 一.mssql sql hashbytes 函数简介 hashbytes函数功能为:返回一个字符,通过 MD2.MD4.MD5. ...

  6. java assert的用法简介【转】

    assert的基本用法 assertion(断言)在软件开发中是一种常用的调试方式,很多开发语言中都支持这种机制,如C,C++和Eiffel等,但是支持的形式不尽相同,有的是通过语言本身.有的是通过库 ...

  7. glVertexAttribPointer 用法简介

    在内存中采用交叉模式存储,向gpu传入顶点数据的方法  GPU: #version 100 attribute highp vec2 aPosition; attribute highp vec2 a ...

  8. C#中IPAddress类/Dns类/IPHostEntry类/IPEndPoint用法简介

    C#中IPAddress类/Dns类/IPHostEntry类/IPEndPoint用法简介 IP是一种普遍应用于因特网.允许不同主机能够相互找到对方的寻址协议.IP地址由4个十进制的数字号码所组成, ...

  9. Postman用法简介----https://blog.csdn.net/flowerspring/article/details/52774399

    https://blog.csdn.net/flowerspring/article/details/52774399 Postman用法简介

随机推荐

  1. Hibernate 一对一关联映射

    package com.entity; import javax.persistence.Entity; import javax.persistence.OneToOne; @Entity publ ...

  2. Hadoop 配置文件简介

    1.core-site.xml文件 这是一个描述集群中NameNode结点的URI-统一资源标识符(包括协议,主机名称,端口号),集群里面的每一台机器都需要知道 NameNode的地址.DataNod ...

  3. C#利用lambda实现委托事件的挂接

    转自:http://www.cdtarena.com/cpx/201307/9287.html在写一个小程序的时候,碰到了这样的问题,需要用委托来挂接事件,但是又想在这事件中使用局部的变量,而委托一旦 ...

  4. 一、Mongo的安装

    注:学习为主,平台为WIN7 32位系统 一.Mongo的安装 1.1 下载 到官方下载地址(http://www.mongodb.org/downloads)去下载所需要的版本 1.2 安装与运行 ...

  5. [教程]安装青鸟云Web服务器

    青鸟云Web服务器 支持的安装环境: Windows XP (32bit) Windows Server 2003/R2 (32bit) Windows 7 (32/64bit) Windows Se ...

  6. CSS:重量和级联规则,确定其优先级

    资源:http://www.ido321.com/1063.html 首先,给大家看一篇关于CSS优先级的演示样例:http://www.ido321.com/76.html 一.主要的优先级规则 比 ...

  7. codeforces #267 C George and Job(DP)

    职务地址:http://codeforces.com/contest/467/problem/C 太弱了..这题当时都没做出来..思路是有的,可是自己出的几组数组总是过不去..今天又又一次写了一遍.才 ...

  8. vi 快捷键积累

    依据自己用到的.或者还没记住的.或者用的时候忘了的,慢慢积累. 一.全选复制粘贴. 全选: ggVG // 凝视: gg 光标移到首行 V 进入Visual(可视)模式 G 光标移到最后一行全选 选中 ...

  9. c语言:链表排序, 链表反转

    下面将实现链表排序的排序和遍历显示功能: 所定义的链表结构如下: head -> p1 -> p2 ->p3 ->....->pn; head的本身不作为数据节点,hea ...

  10. c++,为什么要引入虚拟继承

      虚拟基类是为解决多重继承而出现的.   以下面的一个例子为例: #include <iostream.h> #include <memory.h> class CA { i ...