C语言中回调函数的含义与使用场景详解(2)

 更新时间:2022年03月28日 09:14:21   作者:物联网老王  
这篇文章主要为大家详细介绍了C语言中回调函数的含义与使用场景,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助

详解C语言中回调函数的含义与使用场景(2)

引言:在上一篇文章中介绍了回调函数的概念与使用方法,本节将深入地介绍回调函数典型的使用场景。通过使用回调函数可以实现驱动和应用程序的分离解耦,让程序更加地灵活。也可以借助回调函数实现插入自定义代码、分层设计程序的思想。

使用场景一(重定义):

在统一的接口中,动态地改变一个函数的功能。该函数的功能可以是加载参数、或者执行运算。示例如下:

typedef int (*my_calculate_t)(int a, int b);
static int cal_sum(int a, int b)
{
    printf("now is sum\r\n");
    return a + b;
}
static int cal_sub(int a, int b)
{
    printf("now is sub\r\n");
    return a - b;
}
static int cal_mul(int a, int b)
{
    printf("now is mul\r\n");
    return a * b;
}
static my_calculate_t s_cal = cal_sum;
static int test2_cal (int a, int b)
{
    int result = 0;
    if(s_cal) {
        result = s_cal(a ,b);
        printf("result=%d\r\n", result);
    }
    return result;
}
void app_main(void)
{
    printf("init done\r\n");
    int m = 10, n = 1, ret;
    ret = test2_cal(m, n);
}

上述代码通过 test2_cal() 实现计算接口的统一。只需改变函数指针 s_cal 的值,就可以让 test2_cal()执行不同的功能。我们可以拷贝上述程序分别对 s_cal赋值 cal_sumcal_subcal_mul实现在不改动其他代码的情况下,让 test2_cal 执行不同的运算。这种通过改变函数指针 s_cal 的值,让函数 test2_cal() 执行不同功能的特性,可以称之为重定义test2_cal()的功能。

上述程序运行结果:

init done
now is sum
result=11

使用场景二(扩展函数功能):

可以在程序中定义多个回调函数,若定义了就执行,否则就略过。实现在函数中扩展更多代码的目的(就像一个钩子函数一样)。示例如下:

typedef int (*my_calculate_t)(int a, int b);
static int cal_sum(int a, int b)
{
    printf("now is sum\r\n");
    return a + b;
}
static int cal_sub(int a, int b)
{
    printf("now is sub\r\n");
    return a - b;
}
static int cal_mul(int a, int b)
{
    printf("now is mul\r\n");
    return a * b;
}
static my_calculate_t s_c_array[5] = {cal_sum, cal_sub};
static int test1_cal(int a, int b)
{
    volatile int result = 0;
    volatile size_t i = 0;
    for(i=0; i<(sizeof(s_c_array)/sizeof(my_calculate_t)); i++) {
        if (s_c_array[i] != NULL){
            result = s_c_array[i](a, b);
            printf("i=%d, result=%d\r\n",i, result);
        }
    }
    return result;
}
static void my_cal_calculate_register(my_calculate_t cal)
{
    for(size_t i=0; i<(sizeof(s_c_array)/sizeof(my_calculate_t)); i++) {
        if (s_c_array[i] == NULL){
            s_c_array[i] = cal;
            return;
        }
    }
}
static void my_cal_calculate_unregister(my_calculate_t cal)
{
    for(size_t i=0; i<(sizeof(s_c_array)/sizeof(my_calculate_t)); i++) {
        if (s_c_array[i] == cal){
            s_c_array[i] = NULL;
            return;
        }
    }
}
void app_main(void)
{
    printf("init done\r\n");
    int m = 10, n = 2, ret;
    printf("test 1***************begin\r\n");
    test1_cal(m, n);
    printf("test 1***************end\r\n");
    printf("test 2***************begin\r\n");
    my_cal_calculate_register(cal_mul);
    test1_cal(m, n);
    printf("test 2***************end\r\n");
    printf("test 3***************begin\r\n");
    my_cal_calculate_unregister(cal_mul);
    test1_cal(m, n);
    printf("test 3***************begin\r\n");
}

上述代码通过在函数 test1_cal()增加一个指针数组 s_c_array[] 来控制函数 test1_cal()中实际执行调用哪些函数。默认的情况下,它仅调用 cal_sum 和 cal_sub两个函数,通过函数 my_cal_calculate_register()可以增加它调用的函数,示例中 my_cal_calculate_register(cal_mul);语句增加了其内部调用一个 cal_mul函数。

运行结果:

init done
test 1***************begin
now is sum
i=0, result=12
now is sub
i=1, result=8
test 1***************end
test 2***************begin
now is sum
i=0, result=12
now is sub
i=1, result=8
now is mul
i=2, result=20
test 2***************end
test 3***************begin
now is sum
i=0, result=12
now is sub
i=1, result=8
test 3***************begin
 

使用场景三(分层):

通过在结构体中使用 函数指针来实现程序的分层设计。分层带来的好处是方便维护与结构清晰。

typedef int (*my_calculate_t)(int a, int b);
typedef int (*add_self_t)(int a);
typedef void (*send_to_printf_t)(int a);
typedef struct my_test_struct_t
{
    my_calculate_t m_calculate;
    add_self_t m_add;
    send_to_printf_t m_printf;
}my_test_struct_t;
static int cal_sub(int a, int b)
{
    printf("now is sum\r\n");
    return a - b;
}
static int cal_add_self(int a)
{
    return a+1;
}
static void cal_send_to_printf(int a)
{
    printf("total is %d\r\n", a);
}
static void cal_send_to_printf2(int a)
{
    printf("now total is %d\r\n", a);
}
my_test_struct_t s_test = {
    .m_calculate = cal_sub,
    .m_add = cal_add_self,
    .m_printf = cal_send_to_printf,
};
static int test1_cal(int a, int b)
{
    int result = 0;
    if(s_test.m_calculate){
        result = s_test.m_calculate(a,b);
        printf("result1 is %d\r\n", result);
    }
    if(s_test.m_add){
        result = s_test.m_add(result);
        printf("result1 is %d\r\n", result);
    }
    if(s_test.m_printf) {
        s_test.m_printf(result);
    }
    return result;
}
void app_main(void)
{
    printf("init done\r\n");
    int m = 10, n = 2;
    printf("test 1***************begin\r\n");
    test1_cal(m, n);
    printf("test 1***************end\r\n");
    printf("test 2***************begin\r\n");
    s_test.m_printf = cal_send_to_printf2;
    test1_cal(m, n);
    printf("test 2***************end\r\n");
}

上述程序中通过在结构体 s_test中使用三个函数指针 m_calculatem_addm_printf来实现三个步骤:计算、自增、打印,三层功能的分层。每个层都是一个函数指针,所以每一层都可以通过改变函数指针的值,实现重新定义。

运行结果:

init done
test 1***************begin
now is sum
result1 is 8
result1 is 9
total is 9
test 1***************end
test 2***************begin
now is sum
result1 is 8
result1 is 9
now total is 9
test 2***************end
 

总结

本篇内容作为上一篇文章的深化,重点讲述了回调函数的三种典型使用场景:

  • 实现函数功能重定义
  • 扩展函数功能
  • 实现程序分层设计

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注脚本之家的更多内容!    

相关文章

  • C++中静态数据成员使用示例

    C++中静态数据成员使用示例

    大家好,本篇文章主要讲的是C++中静态数据成员使用示例,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下,方便下次浏览
    2022-01-01
  • c语言中return与exit的区别浅析

    c语言中return与exit的区别浅析

    c语言中return与exit的区别浅析,需要的朋友可以参考一下
    2013-03-03
  • C++ 命名空间 using声明使用示例详解

    C++ 命名空间 using声明使用示例详解

    这篇文章主要为大家介绍了C++ 命名空间 using声明使用示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-12-12
  • C++中的std::initializer_list使用解读

    C++中的std::initializer_list使用解读

    这篇文章主要介绍了C++中的std::initializer_list使用,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-07-07
  • C语言链表实现通讯录系统课程设计

    C语言链表实现通讯录系统课程设计

    这篇文章主要为大家详细介绍了C语言链表实现通讯录系统课程设计,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-06-06
  • C++线程安全的队列你了解嘛

    C++线程安全的队列你了解嘛

    这篇文章主要为大家详细介绍了C++线程安全的队列,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-03-03
  • 纯C++代码详解二叉树相关操作

    纯C++代码详解二叉树相关操作

    二叉树(Binary tree)是树形结构的一个重要类型。许多实际问题抽象出来的数据结构往往是二叉树形式。本文将通过代码为大家详细讲讲C++二叉树的一些常规操作,感兴趣的可以学习一下
    2022-07-07
  • C++ 自增自减运算符的实现示例

    C++ 自增自减运算符的实现示例

    本文主要介绍了C++ 自增自减运算符的实现示例,自增和自减运算符在C++中主要用于循环语句中,使循环变量的值自动+1或者-1,具有一定的参考价值,感兴趣的可以了解一下
    2023-08-08
  • C++的matlab接口转换方法详解

    C++的matlab接口转换方法详解

    这篇文章主要为大家详细介绍了C++的matlab接口转换方法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-03-03
  • c语言中位字段与结构联合的组合使用详解

    c语言中位字段与结构联合的组合使用详解

    本篇文章是对c语言中位字段与结构联合的组合使用进行了详细的分析介绍,需要的朋友参考下
    2013-05-05

最新评论