回呼函數就好像是一個中斷處理函數,系統在符合你設定的條件時自動調用。為此,你需要做三件事:
1. 聲明;
2. 定義;
3. 設定觸發條件,就是在你的函數中把你的回呼函數名稱轉化為地址作為一個參數,以便於系統調用。
申明就是申明一個函數指標;
定義就是實現回呼函數;
觸發條件就是講你定義的函數賦值給一個回呼函數的指標,調用時,就用這個指標帶上函數的參數調用;
1)普通的回呼函數
(1 )函數指標
回調在C語言中是通過函數指標來實現的,通過將回呼函數的地址傳給被調函數從而實現回調。因此,要實現回調,必須首先定義函數指標,請看下面的例子:
void Func(char *s);//函數原型
void (*pFunc) (char *);//函數指標
可以看出,函數的定義和函數指標的定義非常類似。
一般的化,為了簡化函數指標類型的變數定義,提高程式的可讀性,我們需要把函數指標類型自訂一下。
typedef void(*pcb)(char *);
回呼函數可以象普通函數一樣被程式調用,但是只有它被當作參數傳遞給被調函數時才能稱作回呼函數。
被調函數的例子:
void GetCallBack(pcb callback)
{
/*do something*/
}
使用者在調用上面的函數時,需要自己實現一個pcb類型的回呼函數:
void fCallback(char *s)
{
/* do something */
}
然後,就可以直接把fCallback當作一個變數傳遞給GetCallBack,
GetCallBack(fCallback);
如果賦了不同的值給該參數,那麼調用者將調用不同地址的函數。賦值可以發生在運行時,這樣使你能實現動態綁定。
2)回呼函數作為函數的參數使用
這種方法在封裝SDK時很普遍的用到,比如海康和大華的SDK;
比如海康的DVR 預覽SDK:
NET_DVR_API LONG __stdcall NET_DVR_RealPlay_V30(LONG lUserID, LPNET_DVR_CLIENTINFO lpClientInfo, void(CALLBACK *fRealDataCallBack_V30) (LONG lRealHandle, DWORD dwDataType, BYTE *pBuffer, DWORD
dwBufSize, void* pUser) = NULL, void* pUser = NULL, BOOL bBlocked = FALSE);
NET_DVR_CLIENTINFO ClientInfo;
ClientInfo.hPlayWnd = GetDlgItem(IDC_STATIC_PLAY)->m_hWnd;
ClientInfo.lChannel = m_struDeviceInfo.struChanInfo[m_iCurChanIndex].iChanIndex;
ClientInfo.lLinkMode = 0;
ClientInfo.sMultiCastIP = NULL;
TRACE("Channel number:%d\n",ClientInfo.lChannel);
m_lPlayHandle = NET_DVR_RealPlay_V30(m_struDeviceInfo.lLoginID,&ClientInfo,NULL,NULL,TRUE);
3)如果回呼函數不用做函數的參數,也可以通過一個Init函數,將回呼函數傳遞給類的成員變數,然後在類裡面就可以用成員變數進行回調。