C語言中回調(diào)函數(shù)的含義與使用場景詳解
舉例
在下述程序中函數(shù) test2_cal()
中調(diào)用 函數(shù)指針 s_cal 指定的函數(shù)
執(zhí)行數(shù)值的計算。則 s_cal 指定的那些函數(shù)
就可以看作一個回調(diào)函數(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_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); }
上述程序中 s_cal 的值為 cal_sum()
,函數(shù) cal_sum()
就是一個回調(diào)函數(shù);即當(dāng)前要執(zhí)行的運算為 cal_sum
定義的加法運算。
當(dāng)前程序的輸出結(jié)果:
init done
now is sum
result=11
也可以改變 s_cal 的值為 cal_sub
,cal_mul
,它們分別對應(yīng)減法、乘法運算。讀者可自行賦值進(jìn)行測試。
小結(jié):從上述測試,我們不難理解,僅僅通過更改一個 s_cal
函數(shù)指針的值分別指向cal_sum
,cal_sub
,cal_mul
就可以實現(xiàn)整個程序運行不同的運算。運算的接口被統(tǒng)一為 test2_cal()
,它具備了執(zhí)行多種運算的功能(通過更改s_cal
函數(shù)指針的值指定其功能)。另外,從該示例中,對于回調(diào)函數(shù),我們還認(rèn)識到它往往具有一個外殼
,如本例中的 test2_cal()
就是外殼,和一個核心
,即函數(shù)指針,如本例中的 s_cal
函數(shù)指針。
回調(diào)對于編寫庫文件有很大的好處,比如我們要實現(xiàn)一個加法,但加法分很多種:整數(shù)的加法、字符串的加法、指針的加法等等。我們可以定義一個統(tǒng)一的 add()
,并在 add()
中定義一個函數(shù)指針s_add
,通過更改s_add
所指的函數(shù),來適應(yīng)多種數(shù)據(jù)類型的加法。這在C++ 中被稱為“多態(tài)”,即根據(jù)輸入的數(shù)據(jù)類型,調(diào)用符合該數(shù)據(jù)類型運算的函數(shù)。
同樣的,在編寫驅(qū)動程序時,由于不同的設(shè)備具備不同的特性,初始化時的內(nèi)容可能不一樣。使用回調(diào)函數(shù),可以通過改變對應(yīng)的函數(shù)指針的值,來指向不同的設(shè)備的初始化函數(shù),實現(xiàn)能夠兼容許多設(shè)備的驅(qū)動程序。
動態(tài)改變回調(diào)函數(shù)的實現(xiàn)的方法:
如上所示,回調(diào)函數(shù)是通過函數(shù)指針來調(diào)用的。因此想改變回調(diào)函數(shù)的功能,就是研究如何改變函數(shù)指針的值。主要有以下三種方法:
1)編譯時直接賦值
如上一節(jié)所示的示例,通過對函數(shù)指針 s_cal
賦值,可以改變函數(shù) test2_cal()
實際運行的計算。這在編譯時就知道要將函數(shù)指針 s_cal
賦予的值的情況下,可以使用。若在編譯的時候不知道具體要將 s_cal
賦予什么值,或者需要程序運行時動態(tài)地改變 s_cal
的值,直接賦值的方法無法正常使用。
2)運行時實現(xiàn)動態(tài)注冊
運行時,可以通過其他函數(shù)對函數(shù)指針進(jìn)行賦值,在程序運行的時候,動態(tài)地改變函數(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_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; } static void my_cal_calculate_register(my_calculate_t cal) { s_cal = cal; } static void my_cal_calculate_unregister(void) { s_cal = NULL; } void app_main(void) { printf("init done\r\n"); int m = 10, n = 2, ret; ret = test2_cal(m, n); my_cal_calculate_register(cal_sub); ret = test2_cal(m, n); my_cal_calculate_unregister(); my_cal_calculate_register(cal_mul); ret = test2_cal(m, n); my_cal_calculate_unregister(); }
運行結(jié)果:
init done
now is sum
result=12
now is sub
result=8
now is mul
result=20
小結(jié):上述程序通過函數(shù) my_cal_calculate_register()
動態(tài)地改變函數(shù)指針s_cal
的值,從而實現(xiàn)在函數(shù)中動態(tài)地改變test2_cal
功能的目的。一些庫文件的源代碼是不開放的,因此,一些庫中使用這種通過動態(tài)注冊函數(shù)的方法來動態(tài)地指定庫函數(shù)實際功能。
3)作為函數(shù)參數(shù)傳遞到指定的函數(shù)內(nèi)
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 int test1_cal (my_calculate_t actual_cal, int a, int b) { int result = 0; result = actual_cal(a ,b); printf("result=%d\r\n", result); return result; } void app_main(void) { printf("init done\r\n"); int m = 10, n = 2, ret; ret = test1_cal(cal_sum, m, n); ret = test1_cal(cal_sub, m, n); ret = test1_cal(cal_mul, m, n); }
運行結(jié)果:
init done
now is sum
result=12
now is sub
result=8
now is mul
result=20
小結(jié):上面的示例在調(diào)用 test1_cal() 時,通過傳遞要運行的運算函數(shù),實現(xiàn)同一個函數(shù)test1_cal
執(zhí)行多個功能。同名函數(shù)傳遞不同參數(shù)執(zhí)行不同的功能,也是增強(qiáng)函數(shù)兼容性的常見方法。
總結(jié)
本篇文章重點簡述了回調(diào)、回調(diào)函數(shù)的概念。本質(zhì)上,回調(diào)函數(shù)是 C 語言中 函數(shù)指針
的一種用法。回調(diào)函數(shù)用于在統(tǒng)一的接口內(nèi),實現(xiàn)可以動態(tài)地改變函數(shù)的功能。
回調(diào)函數(shù)的實現(xiàn)至少需要兩個函數(shù),一個是外殼,一個是可以通過函數(shù)指針指定實際的被執(zhí)行的函數(shù)。
動態(tài)改變回調(diào)函數(shù)的實現(xiàn)的方法主要有三種:
- 編譯時直接賦值
- 運行時實現(xiàn)動態(tài)注冊
- 作為函數(shù)參數(shù)傳遞到指定的函數(shù)內(nèi)
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
最短時間學(xué)會基于C++實現(xiàn)DFS深度優(yōu)先搜索
常見使用深度優(yōu)先搜索(DFS)以及廣度優(yōu)先搜索(BFS)這兩種搜索,今天我們就來講講什么是深度優(yōu)先搜索,感興趣的可以了解一下2021-08-08Android App仿微信界面切換時Tab圖標(biāo)變色效果的制作方法
這篇文章主要介紹了Android App仿微信界面切換時Tab圖標(biāo)變色效果的制作方法,重點講解了圖標(biāo)的繪制技巧,需要的朋友可以參考下2016-04-04C++實現(xiàn)LeetCode(108.將有序數(shù)組轉(zhuǎn)為二叉搜索樹)
這篇文章主要介紹了C++實現(xiàn)LeetCode(108.將有序數(shù)組轉(zhuǎn)為二叉搜索樹),本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07C++中構(gòu)造函數(shù)與析構(gòu)函數(shù)的調(diào)用順序詳解
C++ 語言一直被批評太復(fù)雜了,很多細(xì)節(jié)的地方需要仔細(xì)推敲,甚至其構(gòu)造函數(shù)和析構(gòu)的調(diào)用順序也成為了一個讓人迷惑的問題,在此我做了簡單的總結(jié)。這篇文章主要介紹了C++中構(gòu)造函數(shù)與析構(gòu)函數(shù)的調(diào)用順序,需要的朋友可以參考借鑒。2017-01-01