很久沒(méi)寫燒腦文了,今天來(lái)寫一篇。
說(shuō)來(lái)奇怪,昨晚睡覺(jué)前,突然在想一個(gè)問(wèn)題:函數(shù)指針有啥用?有啥意義?
(相關(guān)資料圖)
起源是之前有個(gè)學(xué)員問(wèn)我這個(gè)問(wèn)題,但是感覺(jué)當(dāng)時(shí)回答得不是特別好。
有些東西就是這樣,自己知道該怎么用,用在哪,但如果一下子讓我很通俗易懂地表達(dá)出來(lái),腦子就卡殼了。
昨晚夜深人靜,我想到了正好我們wifi報(bào)警主機(jī)那個(gè)項(xiàng)目有個(gè)例子,非常適合去深刻理解。
這個(gè)項(xiàng)目我們對(duì)接的是涂鴉云平臺(tái),然后涂鴉云提供SDK,我們需要移植到我們自己的項(xiàng)目里去。
在移植的過(guò)程中,我們需要去更改他們SDK里面的代碼,我覺(jué)得這點(diǎn)是可以優(yōu)化的。
下面給大家舉一個(gè)具體的例子:
比如我們使用的涂鴉云提供的WiFi模組,通過(guò)串口和我們單片機(jī)連接,有一個(gè)通訊協(xié)議,但是涂鴉云幫我們做好了這個(gè)通訊協(xié)議的代碼,所以會(huì)提供一個(gè)SDK給我們。
我們?cè)谑褂肧DK的時(shí)候,需要修改SDK的代碼,把我們這款單片機(jī)的串口發(fā)送一個(gè)字節(jié)的函數(shù),移植到SDK里面去。
Hal_Wifi_SendByte函數(shù)是STM32的串口發(fā)送一個(gè)字節(jié)函數(shù)。
我們要把這個(gè)函數(shù)放到涂鴉云SDK protocol.c文件的usart_transmit_output函數(shù)里面去。
最終SDK是調(diào)用usart_transmit_output函數(shù)實(shí)現(xiàn)串口數(shù)據(jù)流發(fā)送功能。
Ok,我們現(xiàn)在思考一下,這種方式有什么問(wèn)題?如何解決?
問(wèn)題1:
如果采用這種方式,有一種功能實(shí)現(xiàn)不了,就是假設(shè)涂鴉云這個(gè)SDK要封庫(kù)(lib文件),源碼不開放,我們就沒(méi)法把Hal_Wifi_SendByte放到protocol.c文件的usart_transmit_output函數(shù)里面去。
是不是會(huì)有這個(gè)問(wèn)題?這意味著,protocol.c必須開源,但是很多企業(yè)有一些核心代碼,是商業(yè)機(jī)密,不能開放的,比如做導(dǎo)航的地圖數(shù)據(jù)庫(kù)。
問(wèn)題2:
客戶的技術(shù)水平層次不齊,如果有些基礎(chǔ)稍微差點(diǎn)的,把SDK改亂了,這樣會(huì)增加涂鴉云技術(shù)支持的人工成本。
所以,如果我去做,最理想的是不讓客戶改SDK的任何代碼,你就直接按照我的方法和流程,調(diào)用函數(shù)用。
怎么解決這個(gè)問(wèn)題?那就必須要用函數(shù)指針了!記住,是必須!
第一步:在protocol.h文件下自定一個(gè)函數(shù)指針類型pUart_transmit_output。
第二步:在protocol.c定義一個(gè)函數(shù)指針變量Uart_transmit_outputCBS。
第三步:修改protocol.c文件下uart_transmit_output函數(shù),直接調(diào)用剛剛定義的函數(shù)指針變量Uart_transmit_outputCBS,記住調(diào)用前,必須要指針不為空的條件判斷,否則,如果指針調(diào)用前沒(méi)正確指向,會(huì)造成指針異常,程序死機(jī)。
第四步:在protocol.c文件下編寫Uart_transmit_outputCBS函數(shù)指針的注冊(cè)函數(shù),也就是讓這個(gè)函數(shù)指針變量指向一個(gè)地址的函數(shù)接口。
為什么要單獨(dú)寫個(gè)函數(shù)呢?因?yàn)槲覀兝硐氲那闆r下,是提供函數(shù)接口,給別的.c文件調(diào)用,而不是用全局變量的形式。
第五步:別忘記在protocol.h文件下聲明下Uart_transmit_outputCBSRegister函數(shù),否則別的.c文件無(wú)法調(diào)用這個(gè)函數(shù)。
第六步:在我們單片機(jī)串口驅(qū)動(dòng)文件hal_usart.c的初始化函數(shù)hal_UsartInit里面調(diào)用Uart_transmit_outputCBSRegister函數(shù),然后把hal_Wifi_SendByte函數(shù)地址作為形參傳遞進(jìn)去。
當(dāng)然,在此之前別忘記在hal_usart.c文件的開頭include SDK相關(guān)頭文件。
最終分析:這樣操作完以后,結(jié)果會(huì)是怎樣?
Protocol.c文件下,調(diào)用uart_transmit_outputCBS函數(shù)指針時(shí),是不是等同于調(diào)用hal_usart.c的hal_Wifi_SendByte函數(shù)?
這就是函數(shù)指針的作用,這樣就能實(shí)現(xiàn),客戶不修改SDK代碼,SDK也能調(diào)用客戶工程下.c文件里的函數(shù)了。
這些技巧不復(fù)雜,就像紗窗,有人指點(diǎn)一下,很快就捅破了,沒(méi)人指點(diǎn),可能很多年都領(lǐng)悟不了,這也是進(jìn)階架構(gòu)師必須要掌握的技巧。
審核編輯:湯梓紅
標(biāo)簽: