網站首頁 編程語言 正文
舉例
在下述程序中函數 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"); 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()
,函數 cal_sum()
就是一個回調函數;即當前要執行的運算為?cal_sum
?定義的加法運算。
當前程序的輸出結果:
init done
now is sum
result=11
也可以改變 s_cal 的值為?cal_sub
,cal_mul
,它們分別對應減法、乘法運算。讀者可自行賦值進行測試。
?
小結:從上述測試,我們不難理解,僅僅通過更改一個?s_cal
函數指針的值分別指向cal_sum
,cal_sub
,cal_mul
就可以實現整個程序運行不同的運算。運算的接口被統一為?test2_cal()
,它具備了執行多種運算的功能(通過更改s_cal
函數指針的值指定其功能)。另外,從該示例中,對于回調函數,我們還認識到它往往具有一個外殼
,如本例中的?test2_cal()
就是外殼,和一個核心
,即函數指針,如本例中的?s_cal
函數指針。
回調對于編寫庫文件有很大的好處,比如我們要實現一個加法,但加法分很多種:整數的加法、字符串的加法、指針的加法等等。我們可以定義一個統一的?add()
,并在?add()
中定義一個函數指針s_add
,通過更改s_add
所指的函數,來適應多種數據類型的加法。這在C++ 中被稱為“多態”,即根據輸入的數據類型,調用符合該數據類型運算的函數。
同樣的,在編寫驅動程序時,由于不同的設備具備不同的特性,初始化時的內容可能不一樣。使用回調函數,可以通過改變對應的函數指針的值,來指向不同的設備的初始化函數,實現能夠兼容許多設備的驅動程序。
動態改變回調函數的實現的方法:
如上所示,回調函數是通過函數指針來調用的。因此想改變回調函數的功能,就是研究如何改變函數指針的值。主要有以下三種方法:
1)編譯時直接賦值
如上一節所示的示例,通過對函數指針?s_cal
賦值,可以改變函數?test2_cal()
實際運行的計算。這在編譯時就知道要將函數指針?s_cal
賦予的值的情況下,可以使用。若在編譯的時候不知道具體要將?s_cal
賦予什么值,或者需要程序運行時動態地改變?s_cal
的值,直接賦值的方法無法正常使用。
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; } 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(); }
運行結果:
init done
now is sum
result=12
now is sub
result=8
now is mul
result=20
小結:上述程序通過函數?my_cal_calculate_register()
動態地改變函數指針s_cal
的值,從而實現在函數中動態地改變test2_cal
功能的目的。一些庫文件的源代碼是不開放的,因此,一些庫中使用這種通過動態注冊函數的方法來動態地指定庫函數實際功能。
3)作為函數參數傳遞到指定的函數內
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); }
運行結果:
init done
now is sum
result=12
now is sub
result=8
now is mul
result=20
小結:上面的示例在調用 test1_cal() 時,通過傳遞要運行的運算函數,實現同一個函數test1_cal
執行多個功能。同名函數傳遞不同參數執行不同的功能,也是增強函數兼容性的常見方法。
總結
本篇文章重點簡述了回調、回調函數的概念。本質上,回調函數是 C 語言中?函數指針
?的一種用法。回調函數用于在統一的接口內,實現可以動態地改變函數的功能。
回調函數的實現至少需要兩個函數,一個是外殼,一個是可以通過函數指針指定實際的被執行的函數。
動態改變回調函數的實現的方法主要有三種:
- 編譯時直接賦值
- 運行時實現動態注冊
- 作為函數參數傳遞到指定的函數內
原文鏈接:https://blog.csdn.net/wangyx1234/article/details/123775440
相關推薦
- 2023-01-23 C語言實現讀取CSV文件的方法詳解_C 語言
- 2022-07-21 TensorRT之mmdeploy使用
- 2022-10-02 C++?電話號碼的字母組合功能實現_C 語言
- 2022-09-01 Android使用Intent傳遞組件大數據_Android
- 2022-10-17 Android數據存儲方式操作模式解析_Android
- 2022-09-17 詳解redis集群的三種方式_Redis
- 2022-04-10 Blazor數據綁定用法_基礎應用
- 2022-09-04 Go語言之init函數_Golang
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支