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