• 回调函数(转载)


    转自:C语言中的回调函数(Callback Function)      一文搞懂C语言回调函数

    一、回调函数定义及使用场景

    回调函数是一个通过函数指针调用的函数,然后把这个函数(入口地址)作为参数传给其他函数中,由其他函数在运行时来调用。回调函数是由使用者自己实现的。简单来说,就是由别人的函数运行期间来回调你实现的函数。

    这一设计允许了底层代码调用在高层定义的子程序(如图1-1所示)。C语言中回调函数主要通过函数指针的方式实现。

     

     图1-1

    回调的用途十分广泛:

    例如,假设有一个函数,其功能为读取配置文件并由文件内容设置对应的选项。若这些选项由散列值(hash function)所标记,则让这个函数接受一个回调会使得程序设计更加灵活:函数的调用者可以使用所希望的散列算法,该算法由一个将选项名转变为散列值的回调函数实现;因此,回调允许函数调用者在运行时调整原始函数的行为

    回调的另一种用途在于处理信号量。例如一个POSIX程序可能在收到SIGTERM信号时不愿立即终止;为了保证一切运行良好,该程序可以将清理函数注册为SIGTERM信号对应的回调。

    回调亦可以用于控制一个函数是否作为:Xlib允许自定义的谓词(NSPredicate)用于决定程序是否希望处理特定的事件。

    #include <iostream>
    #include <string>
    using namespace std;
    
    typedef void (*FP)(char* s);    //结构体表示函数指针
    void f1(char* s){cout<<s;}
    void f2(char* s){cout<<s;}
    void f3(char* s){cout<<s;}
    
    int main(int argc,char* argv[])
    {
        int funcselector=0;           //定义一个整数用于控制待执行的函数
        void* a[]={f1,f2,f3};   //定义了指针数组,这里a是一个普通指针
        a[0]("Hello World!
    "); //编译错误,指针数组不能用下标的方式来调用函数
    
        FP f[]={f1,f2,f3};      //定义一个函数指针的数组,这里的f是一个函数指针
        
        /* Handle of funselector */       //此处用于处理funselector,控制待执行的函数
        f[funselector]("Hello World!
    "); //正确,函数指针的数组进行下标操作可以进行函数的间接调用
        
        return 0;
    }

    上面一个例子中提现了回调函数的部分作用。这里f1,f2,f3表示三个功能不相同的函数(举例说明:f1实现最大值输出,f2实现平均值输出,f3实现最小值输出)。总结一下回调函数的一些优势:

    采用funcselector作为标志量,选择待执行的函数很方便的控制了函数的流程和工序。

    f1,f2,f3三个特定函数模块化明显,便于设计者去维护、修改。如图1-1所示,很多系统中software library会完全封装,这样开发者只能通过回调函数去修改函数功能。

    分析函数思路更加清晰,在lwip中大量使用回调函数,开发者可以根据回调函数的调用流程分析系统结构。

    二、结构解析

    回调函数主要结构有三部分组成:主函数、调用函数和被调函数(如图1-1所示)。C语言中,被调函数通常以函数指针(指向对应函数的入口地址)的形式出现。 

    这里给出一个最简单的回调函数结构,并解析相关数据结构。

    //定义回调函数
    void PrintfText() 
    {
        printf("Hello World!
    ");
    }
    
    //定义实现回调函数的"调用函数"
    void CallPrintfText(void (*callfuct)())
    {
        callfuct();
    }
    
    //实现函数回调
    int main(int argc,char* argv[])
    {
        CallPrintfText(PrintfText);
        return 0;
    }

    调用函数向其函数中传递 void (*callfuct)(void) 这是一个 void callfuct(void) 函数的入口地址,即PC指针可以通过移动到该地址执行void callfuct(void) 函数,可以通过类比数组来理解。

    实现函数调用中,函数调用了“调用函数”,再在其中进一步调用被“调用函数”。相比于主函数直接调用“被调函数”,这种方法为使用者,而不是开发者提供了灵活的接口。另外,函数入口可以像变量一样设定同样为开发者提供了灵活性。

    示例2:signal函数

    signal的声明:

    void (*signal(int sig, void (*func)(int)))(int)
    #include <stdio.h>
    #include <signal.h>
    
    /* 捕捉到信号后的处理函数 */
    void handlefunc(int sig){  //回调函数
        
        if(SIGINT == sig){
            printf("GOT SIGINT signal
    ");
        }else{
            printf("GOT SIGHUP signal
    ");
        }
    }
    
    int main(){
        //调用函数
        signal(SIGINT,handlefunc); //Ctrl+C信号
        signal(SIGHUP,handlefunc); //终端结束信号
    
        while(1){
            sleep(1);
        }
    
    }

    总结:

    回调函数允许调用者在运行时调整原始函数的行为;

    相对于在主函数中直接调用函数,回调函数为使用者提供了灵活的接口,可以在调用函数的入口(传参)处,像传入变量一样设定函数的功能。

  • 相关阅读:
    封神台靶机练习第一章:SQL注入攻击原理
    java基础复习-自定义注解1(如何自定义注解?)
    java复习预科知识-Markdown学习
    leetcode-888-公平的糖果交换
    leetcode-884-两句话中的不常见单词
    leetcode-139-单词拆分(递归超时,动归解决)
    leetcode-134-加油站
    leetcode-91-解码方法(动态规划和递归两种解法)
    leetcode-56-合并区间
    leetcode-55-跳跃游戏
  • 原文地址:https://www.cnblogs.com/y4247464/p/12241808.html
Copyright © 2020-2023  润新知