【C/C 】浅谈C/C 中函数指针与回调函数
01、函數指針
1.1、函數指針定義
一個函數總是占用一段連續的內存區域,函數名在表達式中有時也會被轉換為該函數所在內存區域的首地址,這和數組名非常類似。我們可以把函數的這個首地址(或稱入口地址)賦予一個指針變量,使指針變量指向函數所在的內存區域,然后通過指針變量就可以找到并調用該函數。這種指針就是函數指針。
簡言之:函數指針其實就是一個指針變量,代表著一段內存。
1.2、函數指針的定義形式
returnType (*pointerName)(param list);
returnType 為函數返回值類型,pointerName 為指針名稱,param list 為函數參數列表。參數列表中可以同時給出參數的類型和名稱,也可以只給出參數的類型,省略參數的名稱,這一點和函數原型非常類似。
返回類型(*函數名)(參數表)
例如下面兩種寫法都是正確的。
「寫法一:」
void (*F_TYPE)(int nParam,char strName); //帶參數變量名
「寫法二:」
void (*F_TYPE)(int,char); //不帶參數變量名
注意事項:注意( )的優先級高于*,第一個括號不能省略,如果寫作returnType pointerName(param list);就成了函數原型,它表明函數的返回值類型為returnType*
1.3、函數指針與typedef
想必大家都能看出來,函數指針的定義是很長一段的,如果每次是用都要寫這么長一段,額,大可不必,因為,typedef能夠解決這個問題。
typedef:程序中的作用一般是取別名,例如下面這個例子,我們把函數指針換個名字。
typedef 返回類型(*新類型)(參數表)
//1.默認原始寫法: void?callbackint(int?a,?int?b,?int?(*pMsg)(int?a,int?b));? //2.typedef優化后: typedef?void?(*PSM)(int?a,?int?b); void?callbackint(int?a,?int?b,?PSM?p);這樣做的好處是,以后只要需要使用int (*pMsg)(int a, int b)的地方我們都能使用PSM p這種方式來替換他。
typedef是C語言基礎,這里不浪費時間在關鍵字上面,感興趣的可以自行了解一下。
02、回調函數
2.1、回調函數定義
百度給的解釋是:
回調函數就是一個被作為參數傳遞的函數。在C語言中,回調函數只能使用函數指針實現,在C 、Python、ECMAscript等更現代的編程語言中還可以使用仿函數或匿名函數。回調函數的使用可以大大提升編程的效率,這使得它在現代編程中被非常多地使用。同時,有一些需求必須要使用回調函數來實現。最著名的回調函數調用有C/C 標準庫stdlib.h/cstdlib中的快速排序函數qsort和二分查找函數bsearch中都會要求的一個與strcmp類似的參數,用于設置數據的比較方法。
關于名詞仿函數,請參考STL源碼剖析中的算法一塊兒,會有非常細致的解釋。
我自己的理解就是:通過參數將函數地址傳入,在多線程中,如果主線程在執行此函數時,通過參數中的函數地址,相當于異步執行了另外一個函數,另外一個函數也就是我們所稱的回調函數,回調函數多用于socket、http等協議中的消息交互處理,回調函數的本質就是C/C 中的函數指針,如上所述。
2.2、回調函數的使用場景
著名的 lone wolf 曾經解釋過這個問題:
其實回調就是一種利用函數指針進行函數調用的過程. 為什么要用回調呢?比如我要寫一個子模塊給你用, 來接收遠程socket發來的命令.當我接收到命令后, 需要調用你的主模塊的函數, 來進行相應的處理.但是我不知道你要用哪個函數來處理這個命令, 我也不知道你的主模塊是什么.cpp或者.h, 或者說, 我根本不用關心你在主模塊里怎么處理它, 也不應該關心用什么函數處理它…… 怎么辦? 使用回調!
什么是回調函數?
回調函數是應用程序提供給Windows系統DLL或其它DLL調用的函數,一般用于截獲消息、獲取系統信息或處理異步事件。應用程序把回調函數的地址指針告訴DLL,而DLL在適當的時候會調用該函數。回調函數必須遵守事先規定好的參數格式和傳遞方式,否則DLL一調用它就會引起程序或系統的崩潰。通常情況下,回調函數采用標準WindowsAPI的調用方式,即__stdcall,當然,DLL編制者可以自己定義調用方式,但客戶程序也必須遵守相同的規定。在__stdcall方式下,函數的參數按從右到左的順序壓入堆棧,除了明確指明是指針或引用外,參數都按值傳遞,函數返回之前自己負責把參數從堆棧中彈出。理解回調函數!
在很多第三方庫中,比如libcurl中:
CURL_EXTERN curl_easy_setopt(CURL* curl,CURLoption option, ...);
就是用了回調函數,通過設置一個函數地址,當我們將內容發送到http請求頁面之后,頁面會通過字節流返回一個stringstream類型數據,里面就是我們請求服務器之后的返回結果,在一些頻繁請求中,你不可能做到每一個都要程序停下來處理,這個時候,就可以使用回調函數來處理,異步通訊。
多線程中:主線程收發數據、子線程處理響應數據。大致都是一個意思。
03、實例重釋
我這里分文件舉一個簡單的例子闡述剛才上面說到的內容。可能內容不夠精煉,大佬請隨意,初學者建議看一下,很好理解。
功能:創建一個函數,傳遞兩個int類型參數,通過回調函數返回其兩個int類型參數的計算結果。
CallBack.h內容如下:
#ifndef?_CALLBACK_H #define?_CALLBACK_H//使用typedef進行簡化代碼,按部就班的寫肯定沒問題 typedef?int?(*PMSGMessage)(int?a,?int?b);//回調函數 int?callbackInt(int?a,?int?b,?PMSGMessage?p);?#endifCallBack.cpp內容如下:
#include? #include?"CallBack.h"using?namespace?std;int?callbackInt(int?a?,int?b,?PMSGMessage?p) {//回調函數實現retrun?p(a,b) }test.cpp函數內容如下:
#include? #include?"CallBack.h" using?namespace?std;int?Multiplication(int?a,?int?b) {//參數檢查(避免出現0)if(?a?==?0?||?b?==?0){cout?<<?"其中有參數為0,結果應避免為0"?<<?endl;return?0;}return?a?*?b; }int?main() {int?n?=?6;int?m?=?11;int?bRet?=?callbackInt(n,m,add);//如果我們用了類,就是函數等都是成員函數,我們這里要帶上域操作符("?::?")cout?<<?"回調函數執行的結果是:"?<<?bRet?<<?endl;?system("pause");return?0; }小結:回調函數的簡單應用大概就是這么多,如果有機會,建議多用點開源庫,那里面很多地方都是用了回調函數機制,而且都是比此例子高級一點的用法,但是基本思想都一樣,不要因為用法高級一點就害怕了,自己寫兩個例子之后,想必對于回調會有更深的理解。
來源:
https://blog.csdn.net/m0_43458204/article/details/116715045
總結
以上是生活随笔為你收集整理的【C/C 】浅谈C/C 中函数指针与回调函数的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 车辆改装前备案还是改装后备案(改装后备案
- 下一篇: C语言实例:3个数从小到大排序