C語(yǔ)言中回調(diào)函數(shù)的含義與使用場(chǎng)景詳解(2)
詳解C語(yǔ)言中回調(diào)函數(shù)的含義與使用場(chǎng)景(2)
引言:在上一篇文章中介紹了回調(diào)函數(shù)的概念與使用方法,本節(jié)將深入地介紹回調(diào)函數(shù)典型的使用場(chǎng)景。通過(guò)使用回調(diào)函數(shù)可以實(shí)現(xiàn)驅(qū)動(dòng)和應(yīng)用程序的分離解耦,讓程序更加地靈活。也可以借助回調(diào)函數(shù)實(shí)現(xiàn)插入自定義代碼、分層設(shè)計(jì)程序的思想。
使用場(chǎng)景一(重定義):
在統(tǒng)一的接口中,動(dòng)態(tài)地改變一個(gè)函數(shù)的功能。該函數(shù)的功能可以是加載參數(shù)、或者執(zhí)行運(yùn)算。示例如下:
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); }
上述代碼通過(guò) test2_cal()
實(shí)現(xiàn)計(jì)算接口的統(tǒng)一。只需改變函數(shù)指針 s_cal
的值,就可以讓 test2_cal()
執(zhí)行不同的功能。我們可以拷貝上述程序分別對(duì) s_cal
賦值 cal_sum
、cal_sub
、cal_mul
實(shí)現(xiàn)在不改動(dòng)其他代碼的情況下,讓 test2_cal 執(zhí)行不同的運(yùn)算。這種通過(guò)改變函數(shù)指針 s_cal
的值,讓函數(shù) test2_cal()
執(zhí)行不同功能的特性,可以稱之為重定義
了test2_cal()
的功能。
上述程序運(yùn)行結(jié)果:
init done
now is sum
result=11
使用場(chǎng)景二(擴(kuò)展函數(shù)功能):
可以在程序中定義多個(gè)回調(diào)函數(shù),若定義了就執(zhí)行,否則就略過(guò)。實(shí)現(xiàn)在函數(shù)中擴(kuò)展更多代碼的目的(就像一個(gè)鉤子函數(shù)一樣)。示例如下:
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"); }
上述代碼通過(guò)在函數(shù) test1_cal()
增加一個(gè)指針數(shù)組 s_c_array[]
來(lái)控制函數(shù) test1_cal()
中實(shí)際執(zhí)行調(diào)用哪些函數(shù)。默認(rèn)的情況下,它僅調(diào)用 cal_sum
和 cal_sub
兩個(gè)函數(shù),通過(guò)函數(shù) my_cal_calculate_register()
可以增加它調(diào)用的函數(shù),示例中 my_cal_calculate_register(cal_mul);
語(yǔ)句增加了其內(nèi)部調(diào)用一個(gè) cal_mul
函數(shù)。
運(yùn)行結(jié)果:
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
使用場(chǎng)景三(分層):
通過(guò)在結(jié)構(gòu)體中使用 函數(shù)指針來(lái)實(shí)現(xiàn)程序的分層設(shè)計(jì)。分層帶來(lái)的好處是方便維護(hù)與結(jié)構(gòu)清晰。
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"); }
上述程序中通過(guò)在結(jié)構(gòu)體 s_test
中使用三個(gè)函數(shù)指針 m_calculate
、m_add
、m_printf
來(lái)實(shí)現(xiàn)三個(gè)步驟:計(jì)算、自增、打印,三層功能的分層。每個(gè)層都是一個(gè)函數(shù)指針,所以每一層都可以通過(guò)改變函數(shù)指針的值,實(shí)現(xiàn)重新定義。
運(yùn)行結(jié)果:
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
總結(jié)
本篇內(nèi)容作為上一篇文章的深化,重點(diǎn)講述了回調(diào)函數(shù)的三種典型使用場(chǎng)景:
- 實(shí)現(xiàn)函數(shù)功能重定義
- 擴(kuò)展函數(shù)功能
- 實(shí)現(xiàn)程序分層設(shè)計(jì)
本篇文章就到這里了,希望能夠給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
C++實(shí)現(xiàn)LeetCode(2.兩個(gè)數(shù)字相加)
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(兩個(gè)數(shù)字相加),本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07C語(yǔ)言交換奇偶位與offsetof宏的實(shí)現(xiàn)方法
offsetof()是C自帶的一個(gè)宏,它的作用就是計(jì)算結(jié)構(gòu)體成員相對(duì)于首地址處的偏移量,下面這篇文章主要給大家介紹了關(guān)于C語(yǔ)言交換奇偶位與offsetof宏的實(shí)現(xiàn)方法,需要的朋友可以參考下2023-02-02C++中std::chrono時(shí)間庫(kù)的全面解析
C++?std::chrono時(shí)間庫(kù)是C++標(biāo)準(zhǔn)庫(kù)提供的一個(gè)時(shí)間處理庫(kù),提供了一個(gè)方便、靈活和精確的時(shí)間處理工具,下面小編就帶大家深入了解一下std::chrono時(shí)間庫(kù)的使用吧2023-10-10手動(dòng)添加bits/stdc++.h到vs2017的詳細(xì)步驟
這篇文章主要介紹了手動(dòng)添加bits/stdc++.h到vs2017的詳細(xì)步驟,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-02-02在Visual Studio使用C++開(kāi)發(fā)Metro應(yīng)用
這篇文章主要介紹了在Visual Studio使用C++開(kāi)發(fā)Metro應(yīng)用的示例,盡管只是一個(gè)Hello world,但可以體現(xiàn)出VS下為開(kāi)發(fā)者提供的方便,需要的朋友可以參考下2015-07-07C++中inet_pton、inet_ntop函數(shù)的用法
這篇文章主要介紹了C++中inet_pton、inet_ntop函數(shù)的用法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-08-08