知識分享:C 語言函數指針之回調函數

2020-12-12 騰訊網

1、 什麼是回調函數?

首先什麼是「回調」呢?

我的理解是:把一段可執行的代碼像參數傳遞那樣傳給其他代碼,而這段代碼會在某個時刻被調用執行,這就叫做回調。

如果代碼立即被執行就稱為同步回調,如果過後再執行,則稱之為異步回調。

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

回調函數不是由該函數的實現方直接調用,而是在特定的事件或條件發生時由另外的一方調用的,用於對該事件或條件進行響應。

2、 為什麼要用回調函數?

因為可以把調用者與被調用者分開,所以調用者不關心誰是被調用者。它只需知道存在一個具有特定原型和限制條件的被調用函數。

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

int Callback() ///

{

// TODO

return 0;

}

int main() ///

{

// TODO

Library(Callback); ///

// TODO

return 0;

}

回調似乎只是函數間的調用,和普通函數調用沒啥區別。

但仔細看,可以發現兩者之間的一個關鍵的不同:在回調中,主程序把回調函數像參數一樣傳入庫函數。

這樣一來,只要我們改變傳進庫函數的參數,就可以實現不同的功能,這樣有沒有覺得很靈活?並且當庫函數很複雜或者不可見的時候利用回調函數就顯得十分優秀

3 、怎麼使用回調函數?

int Callback_1(int a) ///

{

printf("Hello, this is Callback_1: a = %d ", a);

return 0;

}

int Callback_2(int b) ///

{

printf("Hello, this is Callback_2: b = %d ", b);

return 0;

}

int Callback_3(int c) ///

{

printf("Hello, this is Callback_3: c = %d ", c);

return 0;

}

int Handle(int x, int (*Callback)(int)) ///

{

Callback(x);

}

int main()

{

Handle(4, Callback_1);

Handle(5, Callback_2);

Handle(6, Callback_3);

return 0;

}

如上述代碼:可以看到,Handle()函數裡面的參數是一個指針,在main()函數裡調用Handle()函數的時候,給它傳入了函數Callback_1()/Callback_2()/Callback_3()的函數名,這時候的函數名就是對應函數的指針,也就是說,回調函數其實就是函數指針的一種用法。

4 、回調函數實例(很有用)

一個GPRS模塊聯網的小項目,使用過的同學大概知道2G、4G、NB等模塊要想實現無線聯網功能都需要經歷模塊上電初始化、註冊網絡、查詢網絡信息質量、連接伺服器等步驟,這裡的的例子就是,利用一個狀態機函數(根據不同狀態依次調用不同實現方法的函數),通過回調函數的方式依次調用不同的函數,實現模塊聯網功能,如下:

/********* 工作狀態處理 *********/

typedef struct

{

uint8_t mStatus;

uint8_t (* Funtion)(void); //函數指針的形式

} M26_WorkStatus_TypeDef; //M26的工作狀態集合調用函數

/**********************************************

** >M26工作狀態集合函數

***********************************************/

M26_WorkStatus_TypeDef M26_WorkStatus_Tab[] =

{

, //模塊關機

, //模塊開機

, //管腳初始化

, /AT指令配置

, //連接調度中心

, //等待調度中心回復

, //連接前置機

, //等待前置機回復

, //正常工作

, //等待信號回復

, //獲取信號值

, //模塊重啟

}

/**********************************************

** >M26模塊工作狀態機,依次調用裡面的12個函數

***********************************************/

uint8_t M26_WorkStatus_Call(uint8_t Start)

{

uint8_t i = 0;

for(i = 0; i

{

if(Start == M26_WorkStatus_Tab[i].mStatus)

{

return M26_WorkStatus_Tab[i].Funtion();

}

}

return 0;

}

相關焦點

  • STM32Cube HAL庫中斷處理機制,回調函數實現原理
    所以,我們還需要掌握:應用層代碼如何調用HAL庫函數(API接口),以及HAL庫中斷處理機制等相關知識。HAL庫牽涉的內容較多,下面簡單描述一下HAL庫中斷處理,以及相關的回調函數。1HAL庫中斷處理機制之前使用標準外設庫開發時,中斷程序(函數)由我們自己實現。
  • C語言函數調用過程中的內存變化解析
    局部變量的作用域為什麼僅限於函數內?這個調用不是指C 語言上的函數調用的語法,而是在內存的視角下,函數的調用過程。本文將從C 語言調用實例,內存視角,反彙編代碼來探討C 語言函數的調用過程,也可以說是C 語言函數調用過程圖解。通過這個C 語言函數調用過程圖解,同學們將會知道,C 語言函數在調用時,內存空間是怎樣變化的。 要想理解這一個過程還好涉及到函數棧幀的概念。
  • 成員函數指針的一些奇怪行為
    如果你只是使用單繼承,則指向成員函數的指針實際上是指向了這個函數的起始地址,因為在單繼承中,所有基類都共享了同一個this指針。我們看看下面的代碼:因為它們都使用了同一個this指針,一個指向基類成員函數的指針可以被當作是指向Derived2的成員函數指針來使用,不需要進行任何的轉換操作。
  • C語言基礎知識
    C 傳遞指針給函數通過傳遞指針給函數,可以直接修改原參數(實參),而不是引用實參到形參。pow(x, y)函數C 和 Python 語言的 pow(x, y) 方法都是用於返回 (x 的 y 次方) 的值,C 語言中其原型為:double pow(double x, double y)。
  • c++ 內存,虛函數,運算函數,三角函數
    new 和 delete 運算符== 與equal,簡單的說「equal」比較的是指基本類型比較的是指針最終指向的是數值,"=="比較的是對象地址。這是根本的區別。注意到沒有,引號中的字符 x 被當作普通文本來處理,而不是被當作一個可以被替換的語言符號。假如你確實希望在字符串中包含宏參數,那我們就可以使用「#」 ,它可以把語言符號轉化為字符串。
  • C語言|文件指針、fopen()、fscanf()、fclose()
    這是一個簡單的文件系統fscanf()函數的功能是把磁碟文件數據讀出保存到變量(內存)每一個文件都有自己的FILE結構和文件緩衝區exit(0)是系統標準函數,作用是關閉所有打開的文件參數0表示程序正常結束,非0參數通常表示不正常的程序結束C語言允許同時打開多個文件,不同文件採用不同文件指針指示,但不允許同一個文件在關閉前被再次打開如圖所示,fgets()函數用來從文本文件中讀取字符串,調用格式為:fgets(s,n,fp);其中s可以是字符數組名或字符指針(指向字符串的指針
  • C Primer Plus怎樣高效學?C語言大神案例值得借鑑!
    我們常常聽到有人爭論「Python、Java、PHP......是這個世界上最好的語言」,卻很少聽到有人誇讚C語言,為什麼呢?因為C語言實在是太太太太難了......為什麼這麼多人學不會C語言呢?因為很多人覺得用C語言作為入門語言覺得太難了,裡面還有指針,回調,遞歸之類的操作太難了。
  • C語言主函數main函數返回值有什麼用?
    使用了這麼多年的C語言,學習工作,開發伺服器程序,始終沒有覺得main函數的返回值有什麼作用。最近一段時間由於開發一個測試軟體,需要對考生提交的C源碼和編譯生成的EXE可執行文件進行檢驗,才讓我狠狠地理解了一下main的返回值。
  • 二次函數y=ax2+c的圖像與性質
    因此本課的教學是在學生學過二次函數知識的基礎上,運用圖象變換的觀點把二次函數y=ax2的圖象經過一定的平移變換,而得到二次函數y=ax2+c的圖象。從特殊到一般,最終得到二次函數y=ax2+c的圖象。這樣不僅符合學生的認知規律,而且還使學生進一步體會了數形結合的思想方法,培養了學生的創造性思維的能力和動手實踐能力,突出體現了辯證唯物主義觀點。
  • c語言中sscanf函數的高級用法
    sscanf函數用來從給定字符串中讀取所需數據,用在一些數據轉換時比較方便。常見用法和scanf類似,用%s,%d等獲取字符串和整數。但在%號後可以支持更多的格式,甚至是正則表達式,這樣一來sscanf的功能就比較強大了。
  • 箭頭函數=> 的使用與局限 - ES6中JavaScript新特性之函數
    如果不用箭頭函數,可能就要佔用多行,而且還不如現在這樣寫醒目。箭頭函數的一個用處是簡化回調函數。前者的`this`綁定定義時所在的作用域(即`Timer`函數),後者的`this`指向運行時所在的作用域(即全局對象)。所以,3100 毫秒之後,`timer.s1`被更新了 3 次,而`timer.s2`一次都沒更新。箭頭函數可以讓`this`指向固定化,這種特性很有利於封裝回調函數。下面是一個例子,DOM 事件的回調函數封裝在一個對象裡面。
  • 第五篇:C語言中有關函數的相關知識點梳理
    函數是C語言中,組織程序的最基本的結構單元。我們最初學習C語言的第一個程序就是寫在主函數main()裡面的。在學習函數具體應用之前,我們只認識一個主函數,所有的代碼都必須寫在主函數裡面。01理解「函數」在C語言中,除了主函數、系統函數,還可以根據需要定製函數。
  • C語言編程規範 clean code
    參考該規範之前,希望您具有相應的C語言基礎能力,而不是通過該文檔來學習C語言。了解C語言的ISO標準;熟知C語言的基本語言特性;了解C語言的標準庫;總體原則代碼需要在保證功能正確的前提下,滿足可讀、可維護、安全、可靠、可測試、高效、可移植的特徵要求。
  • 人工智慧數學基礎7:極限、極限運算、ε-δ語言、ε-N語言、級數和函數連續性
    此變量永遠趨近的值A叫做「極限值」ε-δ(epsilon-delta)語言:epsilon-delta語言是用來描述函數極限的語言,其描述如下:對於任意ε>0,存在δ>0,當0<丨x-x0丨<δ時,有丨f(x)-L丨<ε。
  • 逆向XignCode3驅動程序:分析註冊通信和回調函數(part4)
    在分析DriverEntry時,我確定了兩個函數,它們負責不同類型的回調註冊(fn_InitRegistrationNotifyAndCallbackRoutines和fn_RegisterCreateProcessNotifyRoutine
  • 學員問:C語言入門要掌握哪些基礎知識?
    01C語言程序的結構認識用一個簡單的c程序例子,介紹c語言的基本構成、格式、以及良好的書寫風格,使小夥伴對c語言有個初步認識。2、main()——在c語言中稱之為「主函數」,一個c程序有且僅有一個main函數,任何一個c程序總是從main函數開始執行,main函數後面的一對圓括號不能省略。3、被大括號{ }括起來的內容稱為main函數的函數體,這部分內容就是計算機要執行的內容。
  • C語言程序設計試題及答案
    A) 程序行 B) 語句 C) 函數 D) 字符2、C語言規定,在一個源程序中main函數的位置( )。A) 必須在最開始 B) 必須在系統調用的庫函數的後面C) 可以任意 D) 必須在最後3、下列符號串中符合C語言語法的標識符是( )。
  • 一起來討論特殊函數、三角函數誘導公式、基本初等函數圖像的性質
    ①常數函數常值函數(constant function)指值域為一元集的函數,當它為數值函數時常以f(x)=c表示,這裡的c都是constant(常數)的簡寫,常值函數是其值域僅含一個元素的函數。即對該函數定義域一切實數R中的一切X,都有f(x)=a,其中a是一個固定元素。
  • 辦公軟體分享:函數篇 「最」值函數
    關於"最"值函數,對於office2016之前的版本,基本上就是MAX、MIN、MAXA、MINA、DMAX、DMIN函數,office2019(win10)和office365新增函數maxifs和minifs,這裡需要說一下,低端的office版本許多函數和功能是沒有的,比如低端版本沒辦法使用
  • 如何用C語言實現面向對象編程OOP?
    為了簡單起見,我們假設Bird這個結構體中,只有一個函數指針。 其實這個也不難理解,無論是fBird還是Bird,他們在內存中只有一個變量,就是那個函數指針,而void表示任何類型的指針,當我們將它強制轉換成struct Bird類型時,p-》print指向的自然就是傳入實參的print地址。 OOP真的那麼重要?