C語言函數(shù)指針之回調(diào)函數(shù)

1 什么是回調(diào)函數(shù)麦撵?

首先什么是“回調(diào)”呢刽肠?

我的理解是:把一段可執(zhí)行的代碼像參數(shù)傳遞那樣傳給其他代碼,而這段代碼會在某個時刻被調(diào)用執(zhí)行免胃,這就叫做回調(diào)音五。

如果代碼立即被執(zhí)行就稱為同步回調(diào),如果過后再執(zhí)行羔沙,則稱之為異步回調(diào)躺涝。

回調(diào)函數(shù)就是一個通過函數(shù)指針調(diào)用的函數(shù)。如果你把函數(shù)的指針(地址)作為參數(shù)傳遞給另一個函數(shù),當這個指針被用來調(diào)用其所指向的函數(shù)時坚嗜,我們就說這是回調(diào)函數(shù)夯膀。

回調(diào)函數(shù)不是由該函數(shù)的實現(xiàn)方直接調(diào)用,而是在特定的事件或條件發(fā)生時由另外的一方調(diào)用的苍蔬,用于對該事件或條件進行響應诱建。

2 為什么要用回調(diào)函數(shù)?

因為可以把調(diào)用者與被調(diào)用者分開碟绑,所以調(diào)用者不關心誰是被調(diào)用者俺猿。它只需知道存在一個具有特定原型和限制條件的被調(diào)用函數(shù)。

簡而言之格仲,回調(diào)函數(shù)就是允許用戶把需要調(diào)用的方法的指針作為參數(shù)傳遞給一個函數(shù)押袍,以便該函數(shù)在處理相似事件的時候可以靈活的使用不同的方法。

Int Callback()    //< 回調(diào)函數(shù)
{
    // TODO
    return 0;
}
int main()     //<  主函數(shù)
{
    // TODO
    Library(Callback);  //< 庫函數(shù)通過函數(shù)指針進行回調(diào)
    // TODO
    return 0;
}

回調(diào)似乎只是函數(shù)間的調(diào)用凯肋,和普通函數(shù)調(diào)用沒啥區(qū)別谊惭。

但仔細看,可以發(fā)現(xiàn)兩者之間的一個關鍵的不同:在回調(diào)中侮东,主程序把回調(diào)函數(shù)像參數(shù)一樣傳入庫函數(shù)圈盔。

這樣一來,只要我們改變傳進庫函數(shù)的參數(shù)苗桂,就可以實現(xiàn)不同的功能药磺,這樣有沒有覺得很靈活?并且當庫函數(shù)很復雜或者不可見的時候利用回調(diào)函數(shù)就顯得十分優(yōu)秀煤伟。

3 怎么使用回調(diào)函數(shù)?

int Callback_1(int a)   //< 回調(diào)函數(shù)1
{
    printf("Hello, this is Callback_1: a = %d ", a);
    return 0;
}

int Callback_2(int b)  //< 回調(diào)函數(shù)2
{
    printf("Hello, this is Callback_2: b = %d ", b);
    return 0;
}

int Callback_3(int c)   //< 回調(diào)函數(shù)3
{
    printf("Hello, this is Callback_3: c = %d ", c);
    return 0;
}

int Handle(int x, int (*Callback)(int)) //< 注意這里用到的函數(shù)指針定義
{
    Callback(x);
}

int main()
{
    Handle(4, Callback_1);
    Handle(5, Callback_2);
    Handle(6, Callback_3);
    return 0;
}

如上述代碼:可以看到木缝,Handle()函數(shù)里面的參數(shù)是一個指針便锨,在main()函數(shù)里調(diào)用Handle()函數(shù)的時候,給它傳入了函數(shù)Callback_1()/Callback_2()/Callback_3()的函數(shù)名我碟,這時候的函數(shù)名就是對應函數(shù)的指針放案,也就是說,回調(diào)函數(shù)其實就是函數(shù)指針的一種用法矫俺。

4 回調(diào)函數(shù)實例

一個GPRS模塊聯(lián)網(wǎng)的小項目吱殉,使用過的同學大概知道2G、4G厘托、NB等模塊要想實現(xiàn)無線聯(lián)網(wǎng)功能都需要經(jīng)歷模塊上電初始化友雳、注冊網(wǎng)絡、查詢網(wǎng)絡信息質(zhì)量铅匹、連接服務器等步驟押赊,這里的的例子就是,利用一個狀態(tài)機函數(shù)(根據(jù)不同狀態(tài)依次調(diào)用不同實現(xiàn)方法的函數(shù))包斑,通過回調(diào)函數(shù)的方式依次調(diào)用不同的函數(shù)流礁,實現(xiàn)模塊聯(lián)網(wǎng)功能涕俗,如下:

typedef struct
{
 uint8_t mStatus;
 uint8_t (* Funtion)(void); //函數(shù)指針的形式
} M26_WorkStatus_TypeDef;  //M26的工作狀態(tài)集合調(diào)用函數(shù)

/**********************************************
** >M26工作狀態(tài)集合函數(shù)
***********************************************/
M26_WorkStatus_TypeDef M26_WorkStatus_Tab[] =
{    
    {GPRS_NETWORK_CLOSE,  M26_PWRKEY_Off  }, //模塊關機
    {GPRS_NETWORK_OPEN,  M26_PWRKEY_On  }, //模塊開機
    {GPRS_NETWORK_Start,   M26_Work_Init  }, //管腳初始化
    {GPRS_NETWORK_CONF,  M26_NET_Config  }, //AT指令配置
    {GPRS_NETWORK_LINK_CTC,  M26_LINK_CTC  }, //連接調(diào)度中心  
    {GPRS_NETWORK_WAIT_CTC, M26_WAIT_CTC  },  //等待調(diào)度中心回復 
    {GPRS_NETWORK_LINK_FEM, M26_LINK_FEM  }, //連接前置機
    {GPRS_NETWORK_WAIT_FEM, M26_WAIT_FEM  }, //等待前置機回復
    {GPRS_NETWORK_COMM,  M26_COMM   }, //正常工作    
    {GPRS_NETWORK_WAIT_Sig,  M26_WAIT_Sig  },  //等待信號回復
    {GPRS_NETWORK_GetSignal,  M26_GetSignal  }, //獲取信號值
    {GPRS_NETWORK_RESTART,  M26_RESET   }, //模塊重啟
}
/**********************************************
** >M26模塊工作狀態(tài)機,依次調(diào)用里面的12個函數(shù)   
***********************************************/

uint8_t M26_WorkStatus_Call(uint8_t Start)
{
    uint8_t i = 0;
    for(i = 0; i < 12; i++)
    {
        if(Start == M26_WorkStatus_Tab[i].mStatus)
        {          
      return M26_WorkStatus_Tab[i].Funtion();
        }
    }
    return 0;
}

所以神帅,如果有人想做個NB模塊聯(lián)網(wǎng)項目再姑,可以copy上面的框架,只需要修改回調(diào)函數(shù)內(nèi)部的具體實現(xiàn)找御,或者增加元镀、減少回調(diào)函數(shù),就可以很簡潔快速的實現(xiàn)模塊聯(lián)網(wǎng)萎坷。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末凹联,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子哆档,更是在濱河造成了極大的恐慌蔽挠,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,743評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件瓜浸,死亡現(xiàn)場離奇詭異澳淑,居然都是意外死亡,警方通過查閱死者的電腦和手機插佛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評論 3 385
  • 文/潘曉璐 我一進店門杠巡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人雇寇,你說我怎么就攤上這事氢拥。” “怎么了锨侯?”我有些...
    開封第一講書人閱讀 157,285評論 0 348
  • 文/不壞的土叔 我叫張陵嫩海,是天一觀的道長。 經(jīng)常有香客問我囚痴,道長叁怪,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,485評論 1 283
  • 正文 為了忘掉前任深滚,我火速辦了婚禮奕谭,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘痴荐。我一直安慰自己血柳,他們只是感情好,可當我...
    茶點故事閱讀 65,581評論 6 386
  • 文/花漫 我一把揭開白布蹬昌。 她就那樣靜靜地躺著混驰,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上栖榨,一...
    開封第一講書人閱讀 49,821評論 1 290
  • 那天昆汹,我揣著相機與錄音,去河邊找鬼婴栽。 笑死满粗,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的愚争。 我是一名探鬼主播映皆,決...
    沈念sama閱讀 38,960評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼轰枝!你這毒婦竟也來了捅彻?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,719評論 0 266
  • 序言:老撾萬榮一對情侶失蹤鞍陨,失蹤者是張志新(化名)和其女友劉穎步淹,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體诚撵,經(jīng)...
    沈念sama閱讀 44,186評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡缭裆,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,516評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了寿烟。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片澈驼。...
    茶點故事閱讀 38,650評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖筛武,靈堂內(nèi)的尸體忽然破棺而出缝其,到底是詐尸還是另有隱情,我是刑警寧澤徘六,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布氏淑,位于F島的核電站,受9級特大地震影響硕噩,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜缭贡,卻給世界環(huán)境...
    茶點故事閱讀 39,936評論 3 313
  • 文/蒙蒙 一炉擅、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧阳惹,春花似錦谍失、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,757評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春抹竹,著一層夾襖步出監(jiān)牢的瞬間线罕,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,991評論 1 266
  • 我被黑心中介騙來泰國打工窃判, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留钞楼,地道東北人。 一個月前我還...
    沈念sama閱讀 46,370評論 2 360
  • 正文 我出身青樓袄琳,卻偏偏與公主長得像询件,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子唆樊,可洞房花燭夜當晚...
    茶點故事閱讀 43,527評論 2 349