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

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
 

总结

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

实现函数功能重定义

扩展函数功能

实现程序分层设计

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注易知道(ezd.cc)的更多内容!    

推荐阅读

    探探语言设置|探探怎么设置语言

    探探语言设置|探探怎么设置语言,,1. 探探怎么设置语言打开探探软件,然后就有消息提示的红点,点开就行了!其实这些软件都是挺简单的操作的,都是

    git设置编码|git语言设置

    git设置编码|git语言设置,,git设置编码点击cap4j搜索从git直接链接上拉代码。git语言设置Git是一个开源的分布式版本控制系统,可以有效、高

    区域语言设置|区域语言设置工具

    区域语言设置|区域语言设置工具,,区域语言设置工具你好,大致的方法如下,可以参考:1、按下键盘的windows 图标,再开始菜单中单击“设置”;出现的

    c4d语言设置|c4d汉语设置

    c4d语言设置|c4d汉语设置,,1. c4d汉语设置mac版的C4D是这样的,中文字体是有的,但是是以拼音的形式存在,比如黑体就是ht。中文字体以拼音方式

    电脑宣传语|电脑宣传语言

    电脑宣传语|电脑宣传语言,,1. 电脑宣传语言1.我做好了与你过一辈子的打算,也做好了你随时要走的准备,2.每段青春都会苍老,但我希望记忆里的你

    office语言设置|微软office语言设置

    office语言设置|微软office语言设置,,微软office语言设置一、首先点击桌面左下角“WIN键”。二、弹出选项内点击“所有程序”。三、接着点

    小米设置日语|小米设置日语语言

    小米设置日语|小米设置日语语言,,1. 小米设置日语语言MIUI系统文字目前只支持简体中文、繁体中文、英文、藏文和维吾尔文,不支持日文 2. 小

    易语言开发电脑系统|易语言电脑版

    易语言开发电脑系统|易语言电脑版,,1. 易语言电脑版首先编译——是将程序编译为exe文件,只能在有易语言的机子上运行,独立编译——是将程序