網(wǎng)站首頁(yè) 編程語(yǔ)言 正文
C語(yǔ)言中回調(diào)函數(shù)的含義與使用場(chǎng)景詳解_C 語(yǔ)言
作者:物聯(lián)網(wǎng)老王 ? 更新時(shí)間: 2022-05-31 編程語(yǔ)言舉例
在下述程序中函數(shù) test2_cal()
?中調(diào)用?函數(shù)指針 s_cal 指定的函數(shù)
執(zhí)行數(shù)值的計(jì)算。則?s_cal 指定的那些函數(shù)
就可以看作一個(gè)回調(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()
就是一個(gè)回調(diào)函數(shù);即當(dāng)前要執(zhí)行的運(yùn)算為?cal_sum
?定義的加法運(yùn)算。
當(dāng)前程序的輸出結(jié)果:
init done
now is sum
result=11
也可以改變 s_cal 的值為?cal_sub
,cal_mul
,它們分別對(duì)應(yīng)減法、乘法運(yùn)算。讀者可自行賦值進(jìn)行測(cè)試。
?
小結(jié):從上述測(cè)試,我們不難理解,僅僅通過(guò)更改一個(gè)?s_cal
函數(shù)指針的值分別指向cal_sum
,cal_sub
,cal_mul
就可以實(shí)現(xiàn)整個(gè)程序運(yùn)行不同的運(yùn)算。運(yùn)算的接口被統(tǒng)一為?test2_cal()
,它具備了執(zhí)行多種運(yùn)算的功能(通過(guò)更改s_cal
函數(shù)指針的值指定其功能)。另外,從該示例中,對(duì)于回調(diào)函數(shù),我們還認(rèn)識(shí)到它往往具有一個(gè)外殼
,如本例中的?test2_cal()
就是外殼,和一個(gè)核心
,即函數(shù)指針,如本例中的?s_cal
函數(shù)指針。
回調(diào)對(duì)于編寫(xiě)庫(kù)文件有很大的好處,比如我們要實(shí)現(xiàn)一個(gè)加法,但加法分很多種:整數(shù)的加法、字符串的加法、指針的加法等等。我們可以定義一個(gè)統(tǒng)一的?add()
,并在?add()
中定義一個(gè)函數(shù)指針s_add
,通過(guò)更改s_add
所指的函數(shù),來(lái)適應(yīng)多種數(shù)據(jù)類(lèi)型的加法。這在C++ 中被稱(chēng)為“多態(tài)”,即根據(jù)輸入的數(shù)據(jù)類(lèi)型,調(diào)用符合該數(shù)據(jù)類(lèi)型運(yùn)算的函數(shù)。
同樣的,在編寫(xiě)驅(qū)動(dòng)程序時(shí),由于不同的設(shè)備具備不同的特性,初始化時(shí)的內(nèi)容可能不一樣。使用回調(diào)函數(shù),可以通過(guò)改變對(duì)應(yīng)的函數(shù)指針的值,來(lái)指向不同的設(shè)備的初始化函數(shù),實(shí)現(xiàn)能夠兼容許多設(shè)備的驅(qū)動(dòng)程序。
動(dòng)態(tài)改變回調(diào)函數(shù)的實(shí)現(xiàn)的方法:
如上所示,回調(diào)函數(shù)是通過(guò)函數(shù)指針來(lái)調(diào)用的。因此想改變回調(diào)函數(shù)的功能,就是研究如何改變函數(shù)指針的值。主要有以下三種方法:
1)編譯時(shí)直接賦值
如上一節(jié)所示的示例,通過(guò)對(duì)函數(shù)指針?s_cal
賦值,可以改變函數(shù)?test2_cal()
實(shí)際運(yùn)行的計(jì)算。這在編譯時(shí)就知道要將函數(shù)指針?s_cal
賦予的值的情況下,可以使用。若在編譯的時(shí)候不知道具體要將?s_cal
賦予什么值,或者需要程序運(yùn)行時(shí)動(dòng)態(tài)地改變?s_cal
的值,直接賦值的方法無(wú)法正常使用。
2)運(yùn)行時(shí)實(shí)現(xiàn)動(dòng)態(tài)注冊(cè)
運(yùn)行時(shí),可以通過(guò)其他函數(shù)對(duì)函數(shù)指針進(jìn)行賦值,在程序運(yùn)行的時(shí)候,動(dòng)態(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(); }
運(yùn)行結(jié)果:
init done
now is sum
result=12
now is sub
result=8
now is mul
result=20
小結(jié):上述程序通過(guò)函數(shù)?my_cal_calculate_register()
動(dòng)態(tài)地改變函數(shù)指針s_cal
的值,從而實(shí)現(xiàn)在函數(shù)中動(dòng)態(tài)地改變test2_cal
功能的目的。一些庫(kù)文件的源代碼是不開(kāi)放的,因此,一些庫(kù)中使用這種通過(guò)動(dòng)態(tài)注冊(cè)函數(shù)的方法來(lái)動(dòng)態(tài)地指定庫(kù)函數(shù)實(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); }
運(yù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í),通過(guò)傳遞要運(yùn)行的運(yùn)算函數(shù),實(shí)現(xiàn)同一個(gè)函數(shù)test1_cal
執(zhí)行多個(gè)功能。同名函數(shù)傳遞不同參數(shù)執(zhí)行不同的功能,也是增強(qiáng)函數(shù)兼容性的常見(jiàn)方法。
總結(jié)
本篇文章重點(diǎn)簡(jiǎn)述了回調(diào)、回調(diào)函數(shù)的概念。本質(zhì)上,回調(diào)函數(shù)是 C 語(yǔ)言中?函數(shù)指針
?的一種用法。回調(diào)函數(shù)用于在統(tǒng)一的接口內(nèi),實(shí)現(xiàn)可以動(dòng)態(tài)地改變函數(shù)的功能。
回調(diào)函數(shù)的實(shí)現(xiàn)至少需要兩個(gè)函數(shù),一個(gè)是外殼,一個(gè)是可以通過(guò)函數(shù)指針指定實(shí)際的被執(zhí)行的函數(shù)。
動(dòng)態(tài)改變回調(diào)函數(shù)的實(shí)現(xiàn)的方法主要有三種:
- 編譯時(shí)直接賦值
- 運(yùn)行時(shí)實(shí)現(xiàn)動(dòng)態(tài)注冊(cè)
- 作為函數(shù)參數(shù)傳遞到指定的函數(shù)內(nèi)
原文鏈接:https://blog.csdn.net/wangyx1234/article/details/123775440
相關(guān)推薦
- 2022-08-01 C++簡(jiǎn)單又輕松的講解類(lèi)和對(duì)象中友元函數(shù)_C 語(yǔ)言
- 2023-06-05 Python數(shù)據(jù)分析之堆疊數(shù)組函數(shù)示例總結(jié)_python
- 2023-06-18 深入了解Golang中的Slice底層實(shí)現(xiàn)_Golang
- 2022-04-12 【debug】illegal hardware instruction
- 2022-09-08 Python列表list的詳細(xì)用法介紹_python
- 2022-09-03 ASP.NET中Response.BufferOutput屬性的使用技巧_實(shí)用技巧
- 2022-08-13 Docker(Windows版)安裝zookeeper+kafka
- 2023-02-03 Python3.10?Generator生成器Coroutine原生協(xié)程詳解_python
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過(guò)濾器
- Spring Security概述快速入門(mén)
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡(jiǎn)單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支