回调函数究竟有什么作用??

2022-05-10 08:40:37 浏览数 (1)

《函数指针》

再讲回调函数之前,插播一下函数指针。

函数指针:其本质是一个指针变量,该指针指向这个函数。简单来说,函数指针就是指向函数的指针。

声明格式:类型说明符 (*函数名) (参数)

《回调函数》

回调函数:一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

--某度的解释

根据某度的解释有可能比较绕口;举一个简单的例子,pcb厂家提供打样pcb服务,pcb厂家都会要求客户决定如何制作自己的pcb板子。比如沉金,板子的厚度,SMT贴片等。其中pcb制作是psb厂家提供的服务,相当与库函数;pcb的制作方式要求是客户提出的,相当于回调函数,而客户告诉pcb厂家如何制作pcb的动作,相当于把回调函数传入到库函数,也称为回调函数。

从图片(来自于某网站)可以看到,回调函数通常和应用处于同一层(因为传入什么样的回调函数是在应用层决定的)。而回调就成了一个高层调用底层,底层再回过头来调用高层的过程。

《例子说明》

例子1:

代码语言:javascript复制
#include <stdio.h>

typedef void (*p_fun)();
void call_fun() 
{
    printf("Hello workn");
}

int main()
{
    p_fun fun = call_fun;
    fun();
    return 0;
}

输出结果:

代码语言:javascript复制
Hello work

从这个例子可以看到,我们首先定义了一个函数指针fun,这个函数指针的返回值为void型,然后我们给函数指针赋值,赋值为call_fun,也就是call_fun函数的首地址,此时fun获得了call_fun的地址,fun的地址等于call_fun的地址,所以最终调用fun(),也就相当于调用了call_fun();

不过这个例子并没有实现回调函数本质(函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数),而是反应函数指针的的用法。

例子2:

代码语言:javascript复制
#include <stdio.h>

int doubled(int k)
{
    return 2*k;
}

int quadruple(int k)
{
    return 4*k;
}

int get_odd_number(int k, int (*p_fun)(int))
{
    return (*p_fun)(k)   1;
}

int main()
{
    printf("%dn", get_odd_number(2, doubled));
    printf("%dn", get_odd_number(2, quadruple));

    return 0;
}

输出结果:

代码语言:javascript复制
5
9

这个例子就符合了回调函数的本质了,函数指针作为

get_odd_number函数的型参(符合:函数的指针(地址)作为参数传递给另一个函数)。其中如第20行的代码,函数指针指向doubled函数(符合:这个指针被用来调用其所指向的函数),doubled函数就是回调函数。

不妨你看,这也体现了C语言抽象的设计,上面的例子中分别求(2*k 1)的奇数,(4*k 1)的奇数。他们的共性就是求奇数,所以get_odd_number函数可以看作把它们的共性抽象出来。

例子3:

我们把上面的例子进行拆分为三个文件,并使用Linux环境来解释,创建三个文件:main.c lib.c lib.h。

main.c:

代码语言:javascript复制
#include <stdio.h>
#include "lib.h"

int doubled(int k)
{
    return 2*k;
}

int quadruple(int k)
{
    return 4*k;
}

int main()
{
    printf("%dn", get_odd_number(2, doubled));
    printf("%dn", get_odd_number(2, quadruple));

    return 0;
}

lib.c:

代码语言:javascript复制
#include "lib.h"

int get_odd_number(int k, int (*p_fun)(int))
{
    return (*p_fun)(k)   1;
}

lib.h:

代码语言:javascript复制
#ifndef __LIB_H
#define __LIB_H

int get_odd_number(int k, int (*p_fun)(int));

#endif

制作动态库:

代码语言:javascript复制
rice@rice:~/rice_file$ gcc -shared -fPIC lib.c -o libtest.so
rice@rice:~/rice_file$ sudo cp libtest.so /usr/lib/
rice@rice:~/rice_file$ gcc main.c -L. -ltest -o output
rice@rice:~/rice_file$ ./output 
5
9

生成动态库,参数说明: gcc -shared -fPIC lib.c -o libtest.so

-shared : 生成动态库; -fPIC : 生成与位置无关代码; -o :指定生成的目标文件; 使用动态库,参数说明: gcc main.c -L . –ltest -o output -L : 指定库的路径(编译时); 不指定就使用默认路径(/usr/lib/) -lvendor : 指定需要动态链接的库是谁; 这个例子简单的实现了C的封装封装的方式,对外只提供了API。在linux中很多这种链接库的做事,比如第三方的算法等,只提供API,你看不到算法的实现。回调函数在linux里面用的提多的。动态链接库和静态链接库详细内容请看另外两篇

0 人点赞