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

目录
  • 详解C语言中回调函数的含义与使用场景(2)
    • 使用场景一(重定义):
    • 使用场景二(扩展函数功能):
    • 使用场景三(分层):
  • 总结

详解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

总结

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

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

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

(0)

相关推荐

  • C语言回调函数的简单运用

    目录 一.什么是回调函数 二.简单的回调函数 三.带参数的回调函数 一.什么是回调函数 因为在程序中,我们有很多的库函数,我们也有很多的上层函数,为了增加程序的灵活性,我们就将一些函数指针作为参数传递到函数里面去. 说的粗糙一点,就是将一个函数作为另一个函数的函数参数. 调用回调函数我们需要一个中间函数进行过渡. 这个中间函数的参数是一个函数指针. 二.简单的回调函数 我们来写一个简单的例子,帮助我们理解: #include <stdio.h> /*回调函数1*/ void callBack1

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

    目录 举例 动态改变回调函数的实现的方法: 1)编译时直接赋值 2)运行时实现动态注册 3)作为函数参数传递到指定的函数内 总结 举例 在下述程序中函数 test2_cal() 中调用 函数指针 s_cal 指定的函数执行数值的计算.则 s_cal 指定的那些函数就可以看作一个回调函数. typedef int (*my_calculate_t)(int a, int b); static int cal_sum(int a, int b) { printf("now is sum\r\n&qu

  • C语言中的回调函数实例

    在C语言中一般用typedef来为回调函数定义别名(参数名). 别名通过宏定义typedef来实现,不是简单的宏替换.可以用作同时声明指针型的多个对象. 比如: 复制代码 代码如下: char *pa,pb://pa是一个char型指针,但pb是一个char型字符.我们可以这样来实现typedef char* PCHAR:PCHAR pa,pb://pa和pb都是char型指针 先看一个回调函数的例子: 复制代码 代码如下: #include<stdio.h> //方法指针的格式为:int (

  • C语言中回调函数的使用详情

    目录 1.程序架构 2.回调函数的作用 3.掌握回调函数的程序编写 4.回调函数在产品中的应用 下文将学习到; 程序架构的核心理念和需求 掌握回调函数的作用 掌握回调函数的程序编写 掌握回调函数在产品中的应用 1.程序架构 一个好的程序架构至少要达到以下要求: 硬件层和应用层的程序代码分开,相互之间的控制和通讯使用接口,而且不会共享的全局变量或者数组. 用专业术语描述就是可移植性.可扩展性. 在51单片机写程序时,基本上一个.c文件解决,包括寄存器配置,产品功能.到了stm32时,我们会把不同的

  • c语言中回调函数的使用以及实际作用详析

    目录 前言 一.通过这节课程你能掌握以下知识: 二.程序架构的核心理念和需求 三.回调函数的作用 1.输出型 2.输入型 四.掌握回调函数的程序编写 总结 前言 今天给大家讲一下芯片/模块厂家写SDK必须会使用的一种技术:回调函数. 回调函数这个知识点其实并不是很难,难是难在网上很多讲解回调函数的都说的太学术化了化了,一点也不亲民. 很多人即使知道怎么写回调函数也根本就搞不懂它们在实际产品中也有什么用,什么时候用. 所以这节课呢我们会以程序架构的需求为出发点,讲解回调函数是怎么满足它这个需求的.

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

    目录 详解C语言中回调函数的含义与使用场景(2) 使用场景一(重定义): 使用场景二(扩展函数功能): 使用场景三(分层): 总结 详解C语言中回调函数的含义与使用场景(2) 引言:在上一篇文章中介绍了回调函数的概念与使用方法,本节将深入地介绍回调函数典型的使用场景.通过使用回调函数可以实现驱动和应用程序的分离解耦,让程序更加地灵活.也可以借助回调函数实现插入自定义代码.分层设计程序的思想. 使用场景一(重定义): 在统一的接口中,动态地改变一个函数的功能.该函数的功能可以是加载参数.或者执行运

  • 关于c语言中回调函数的理解

    前言 在计算机程序设计中,回调函数,或简称回调,是指通过函数参数传递到其它代码的,某一块可执行代码的引用.这一设计允许了底层代码调用在高层定义的子程序. 这段话不是那么好理解,不同语言实现回调的方式有些许不同.其实可以这样理解,回调就是在一个函数中调用另外一个函数. 在c语言中,回调是使用函数指针来实现的. 函数指针--顾名思义,是指向一个函数的指针.通常函数指针有两个方面的用途,一个是转换表(jump table),另一个是作为参数传递给一个函数. 下面是两个函数指针的声明 int(*f)(i

  • C语言中回调函数和qsort函数的用法详解

    目录 回调函数 指向函数指针数组的指针 qsort(qulick sort)-库函数 回调函数 通过函数指针调用的函数,如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数. 回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应. 举例: #include<stdio.h> void menu() { printf("*************************

  • Python中zip()函数的解释和可视化(实例详解)

    zip()的作用 先看一下语法: zip(iter1 [,iter2 [...]]) -> zip object Python的内置help()模块提供了一个简短但又有些令人困惑的解释: 返回一个元组迭代器,其中第i个元组包含每个参数序列或可迭代对象中的第i个元素.当最短的可迭代输入耗尽时,迭代器将停止.使用单个可迭代参数,它将返回1元组的迭代器.没有参数,它将返回一个空的迭代器. 与往常一样,当您精通更一般的计算机科学和Python概念时,此模块非常有用.但是,对于初学者来说,这段话只会引发更

  • Go语言中的方法、接口和嵌入类型详解

    概述 在 Go 语言中,如果一个结构体和一个嵌入字段同时实现了相同的接口会发生什么呢?我们猜一下,可能有两个问题: 1.编译器会因为我们同时有两个接口实现而报错吗? 2.如果编译器接受这样的定义,那么当接口调用时编译器要怎么确定该使用哪个实现? 在写了一些测试代码并认真深入的读了一下标准之后,我发现了一些有意思的东西,而且觉得很有必要分享出来,那么让我们先从 Go 语言中的方法开始说起. 方法 Go 语言中同时有函数和方法.一个方法就是一个包含了接受者的函数,接受者可以是命名类型或者结构体类型的

  • ES6中箭头函数的定义与调用方式详解

    本文主要介绍的是关于ES6箭头函数的定义与调用方式的相关内容,分享出来供大家参考学习,下面来看看详细的介绍: 基本用法: ES6中允许使用"箭头"(=>)定义函数 var f = v => v; 上面代码相当于: var f = function( v ) { return v; } 根据箭头函数有参数和无参数来区分 1.无参数的箭头函数 var f = () => 5; 等同于 var f = function() { return 5}; 2.有参数的箭头函数 v

  • PHP中register_shutdown_function函数的基础介绍与用法详解

    前言 最近在看<PHP核心技术与最佳实践>,里面有使用到一个函数,register_shutdown_function,由于之前没有用过该函数,就去查了一下资料,就觉得是个很实用的函数,所以这里写一下这个函数的用法.下面话不多说了,来一起看看详细的介绍吧. 1. 函数说明 定义:该函数是来注册一个会在PHP中止时执行的函数 参数说明: void register_shutdown_function ( callable $callback [, mixed $parameter [, mixe

随机推荐