C语言、嵌入式重点知识:回调函数
前言
上文分享了一個(gè)專(zhuān)用的雙鏈表的基本操作示例:雙鏈表的操作示例(附代碼)
這里提到了一個(gè)關(guān)鍵詞:專(zhuān)用。與專(zhuān)用對(duì)應(yīng)的詞是通用。
我們從字面上可以很容易理解這兩個(gè)詞,專(zhuān)用就是針對(duì)特定情況的,特點(diǎn)就是很有局限性。
通用就是可以針對(duì)大多數(shù)情況(更理想的就是所有情況),特點(diǎn)就是適用性廣。
為什么說(shuō)上篇筆記的雙鏈表是專(zhuān)用的?
從我們的定義的元素?cái)?shù)據(jù)類(lèi)型就可以知道,我們這個(gè)雙鏈表是只是用來(lái)存儲(chǔ)int類(lèi)型的數(shù)據(jù)的,這就很能體現(xiàn)出了局限性(這只是其中一點(diǎn),當(dāng)然還有其它的很多局限性),因此是個(gè)專(zhuān)用的雙鏈表。
我們要編寫(xiě)一個(gè)通用的雙鏈表的話(huà),我們首先要做的是就是修改雙鏈表結(jié)點(diǎn)結(jié)構(gòu)體了,可以修改為:
如果我們要存放整數(shù),我們可以把void*強(qiáng)制轉(zhuǎn)換成整數(shù)使用。當(dāng)然這篇筆記的重點(diǎn)不是分享通用的雙鏈表。
我們這篇筆記要分享的是回調(diào)函數(shù),下面進(jìn)入重點(diǎn)內(nèi)容:
回調(diào)函數(shù)法 VS 常規(guī)法
我們上篇筆記中有一個(gè)打印輸出鏈表數(shù)據(jù)的函數(shù):
這是我們這個(gè)專(zhuān)用的雙鏈表中打印鏈表數(shù)據(jù)函數(shù),我們存儲(chǔ)的是整數(shù),所以用%d打印。那么,如果我們面向的是通用的雙鏈表呢?
我們無(wú)法預(yù)知其中的數(shù)據(jù),可能是整數(shù),也可能是字符串,或者是其它的數(shù)據(jù)。那么怎么辦呢?這里有幾種方法:
方法一:實(shí)現(xiàn)多個(gè)函數(shù),需要用到哪個(gè)就調(diào)哪個(gè)
比如存放的是整數(shù),可以調(diào)用dlist_print_int函數(shù)來(lái)打印;存放的是字符串,可以調(diào)用dlist_print_string函數(shù)來(lái)打印。
這種方法很簡(jiǎn)單,但有個(gè)缺點(diǎn):每個(gè)函數(shù)都很相似,會(huì)有大量重復(fù)的代碼。
方法二:傳入一個(gè)附加的參數(shù)來(lái)選擇打印的方式
這種方法使用一個(gè)參數(shù)來(lái)選擇打印的方式。避免了方法一中產(chǎn)生大量重復(fù)的代碼的問(wèn)題。
但是我們每當(dāng)要增加新類(lèi)型時(shí),都得修改這個(gè)dlist_print函數(shù),對(duì)于一個(gè)通用的雙鏈表來(lái)說(shuō),這樣的修改是不夠好的。
這里dlist_print函數(shù)也是通用雙鏈表的一部分,我們應(yīng)該盡量少去修改它。
假如我們把一個(gè)通用的雙鏈表的基礎(chǔ)操作比喻做一棟樓房的地基,地基一旦牢牢固固的搭好之后,我們就不要再去動(dòng)它了,應(yīng)該把精力放在如何搭建房子的上層上。
方法三:回調(diào)函數(shù)法
上面兩種方法應(yīng)該是很容易想到的方法。現(xiàn)在來(lái)分享我們可能想不到的方法——回調(diào)函數(shù)法,這也是本篇筆記要分享的重點(diǎn)。
可能有很多朋友沒(méi)用過(guò)回調(diào)函數(shù),甚至有些朋友都沒(méi)聽(tīng)說(shuō)過(guò)。這里先簡(jiǎn)單介紹回調(diào)函數(shù)的一些概念(以下概念來(lái)自百度百科):
回調(diào)函數(shù)就是一個(gè)通過(guò)函數(shù)指針調(diào)用的函數(shù)。如果你把函數(shù)的指針(地址)作為參數(shù)傳遞給另一個(gè)函數(shù),當(dāng)這個(gè)指針被用來(lái)調(diào)用其所指向的函數(shù)時(shí),我們就說(shuō)這是回調(diào)函數(shù)。
回調(diào)函數(shù)不是由該函數(shù)的實(shí)現(xiàn)方直接調(diào)用,而是在特定的事件或條件發(fā)生時(shí)由另外的一方調(diào)用的,用于對(duì)該事件或條件進(jìn)行響應(yīng)。
知識(shí)點(diǎn):變量指針指向的是一塊數(shù)據(jù),指針指向不同的變量,則取到的是不同的數(shù)據(jù);函數(shù)指針指向的是一段代碼(即函數(shù)),指針指向不同的函數(shù),則具有不同的行為。
回歸正題,下面看如何使用回調(diào)函數(shù)法來(lái)實(shí)現(xiàn)上面的需求。
首先,我們需要實(shí)現(xiàn)一個(gè)通用的打印函數(shù)dlist_print,把函數(shù)指針變量作為其中一個(gè)參數(shù)傳入。
其次,我們調(diào)用者得根據(jù)實(shí)際情況實(shí)現(xiàn)一個(gè)用于打印的回調(diào)函數(shù),這里我們實(shí)現(xiàn)的的回調(diào)函數(shù)是dlist_print_int。
最后,在用到打印的地方調(diào)用dlist_print函數(shù)即可。
用回調(diào)函數(shù)法是不是很巧妙?
此處,我們用到了typedef來(lái)“封裝”一個(gè)打印鏈表數(shù)據(jù)的函數(shù)指針類(lèi)型,這可能會(huì)刷新了初學(xué)者對(duì)于typedef關(guān)鍵字的認(rèn)識(shí)。
因?yàn)槲覀儎傞_(kāi)始學(xué)C語(yǔ)言的時(shí)候,總認(rèn)為typedef取別名的一般形式為:
typedef 舊名字 新名字;確實(shí)也是這樣,但遇到給函數(shù)指針類(lèi)型、數(shù)組類(lèi)型等定義別名的時(shí)候就要特別區(qū)分了。如:
typedef char ARRAY20[20]; ARRAY20 a1,a2; /* 等價(jià)于char a1[20],a2[20]; */別問(wèn)為什么,就是這樣的。。。
回調(diào)函數(shù)的例子
上面分析了那么多,可能很多朋友會(huì)覺(jué)得回調(diào)函數(shù)太麻煩了,沒(méi)必要用。但是現(xiàn)實(shí)是,回調(diào)函數(shù)在我們的C編程、嵌入式編程中用得很廣泛。
1、在C編程中
在C語(yǔ)言的通用工具庫(kù)stdlib.h中,有如下一個(gè)函數(shù)原型:
void qsort(void *, size_t, size_t, int (comp*)(const void *, const void *));這是在C通用工具庫(kù)中聲明的一個(gè)快速排序算法函數(shù),其可以用來(lái)排序int類(lèi)型、float類(lèi)型以及字符串?dāng)?shù)據(jù)。
可以按從小到大的順序也可以按從大到小的順序排序。其關(guān)鍵在于函數(shù)指針comp指向的函數(shù)的具體實(shí)現(xiàn)。
2、在嵌入式編程中
我們之前的筆記:【RT-Thread筆記】PIN設(shè)備中斷配置中,就有用到回調(diào)函數(shù)。
RT-Thread給我們提供了PIN設(shè)備中斷回調(diào)綁定函數(shù):rt_pin_attach_irq
這是個(gè)中斷實(shí)驗(yàn),產(chǎn)生中斷會(huì)回調(diào)我們的回調(diào)函數(shù),所以可以在在我們的回調(diào)函數(shù)里做一些產(chǎn)生中斷后需要做的操作。
比如我們?cè)谶@個(gè)中斷回調(diào)里打印一串字符串。每當(dāng)中斷來(lái)時(shí),就會(huì)打印該字符串:
總結(jié)
回調(diào)函數(shù)是一個(gè)很重要的知識(shí)點(diǎn),我們需要掌握。而回調(diào)函數(shù)又與函數(shù)指針聯(lián)系密切,我們要努力把函數(shù)指針弄懂、用熟。
在C語(yǔ)言中,指針很重要,函數(shù)指針更重要。正如前輩們常說(shuō)類(lèi)似這樣子的話(huà):不會(huì)C指針,就沒(méi)學(xué)會(huì)C語(yǔ)言;不會(huì)函數(shù)指針,就不要稱(chēng)自己是C語(yǔ)言高手。
在這幾種方法中的分析中,其實(shí)回調(diào)函數(shù)更多的是體現(xiàn)出了軟件分層的思想。分層思想在我們軟件開(kāi)發(fā)中是一種很重要的思想,簡(jiǎn)單的分層我們都會(huì),但是怎么才能算是分層分得很好呢?
那就是不該動(dòng)的地方不動(dòng),該動(dòng)的地方才動(dòng),銜接得很好,就像上面的回調(diào)函數(shù)法。
對(duì)于編程的學(xué)習(xí),關(guān)于編程語(yǔ)言的學(xué)習(xí),知識(shí)點(diǎn)就是那么多,很快就能學(xué)完了,但是真正靈活的、熟練應(yīng)用起來(lái)真的是不容易,這需要我們大量地分析、思考、練習(xí)。
有時(shí)間的話(huà)我們也應(yīng)該多讀讀一些關(guān)于軟件設(shè)計(jì)思想的書(shū)籍,這也是我最近在讀的一類(lèi)書(shū),學(xué)學(xué)前輩們總結(jié)出的一些精華知識(shí)。
最后
以上就是本次關(guān)于回調(diào)函數(shù)的筆記分享,如有錯(cuò)誤,歡迎指出。如果覺(jué)得文章不錯(cuò),轉(zhuǎn)發(fā)、在看,也是我們繼續(xù)更新得動(dòng)力。
? 回復(fù)「?籃球的大肚子」進(jìn)入技術(shù)群聊
回復(fù)「1024」獲取1000G學(xué)習(xí)資料
總結(jié)
以上是生活随笔為你收集整理的C语言、嵌入式重点知识:回调函数的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 这个结构体对齐输出有意思
- 下一篇: Arm 中国原 CEO 被“罢免”,新指