/***************************************************** * Filename: 一線(xiàn)研發(fā)之聲:嵌入式C編程經(jīng)驗 之 函數指針 * Author:SedateFire * E-mail:SedateFire@126.com * Version:1.0 * Modify Date: 2012-01-12 * key: 嵌入式 函數指針 回調函數 * 本文首發(fā): 環(huán)球資源-電子工程專(zhuān)輯-博客: 靜心齋 ******************************************************/ 今天討論什么呢,就討論函數指針吧 指針,在C語(yǔ)言中,是一個(gè)神圣的存在,可遠觀(guān)不可褻玩焉。函數指針,則是指針里面更讓人敬畏的存在。 如果你是一個(gè)單片機工作者,那么我猜測你八成忘記了函數指針如何定義,我幾乎可以想象出你苦苦思索的神態(tài)了。 如果你是一個(gè)linux底層驅動(dòng)工作者,那么顯然你要感嘆造物住的神奇,函數指針竟是如此的遍地開(kāi)花。尤其是linux 2.6以后的內核版本,你幾乎要被指針晃花眼睛了,沒(méi)有2年工作經(jīng)驗你都很難找到函數的原型定義在哪里。linux內核是一個(gè)高度抽象的世界,它把所有外設都視為文件,這一切,函數指針功不可沒(méi)。 前者太遙遠,因為單片機基本上無(wú)法應用函數指針。比如Keil C51,函數指針是非常危險的,因為編譯器不知道你這個(gè)指針要指向那個(gè)函數,也就無(wú)法分析分配每個(gè)局部變量。額...那個(gè)靜態(tài)編譯懂嗎?用一句形象的話(huà)為君解惑,對于靜態(tài)編譯,每個(gè)變量(含局部)它的地址都是恒定不變的,但不是唯一的哦。C51的棧,只用來(lái)存儲函數返回地址。當然,特殊的遞歸編譯不在討論范圍之內。所以,單片機程序和函數指針基本絕緣。只有一個(gè)途徑可以用函數指針,那就是在編譯階段就告訴編譯器這個(gè)函數指針的對象,且那個(gè)函數必須是有定義的,存在的。 static const void (*function_pointer)(void) = function_exist; 如果你的單片機程序中,有一個(gè)很大的很有規律的類(lèi)似switch的寫(xiě)法,那么可以改寫(xiě)成靜態(tài)函數指針數組,用查表方式,無(wú)論是可閱讀性,還是程序效率,都頗有可道之處。如果不告訴編譯器函數指針的對象,那你就完蛋了,程序也許能跑,但bug是莫名其妙的,沒(méi)有任何邏輯的。如果你說(shuō)那樣干沒(méi)有問(wèn)題,那我也不爭辯,只盼你能買(mǎi)幾張彩票送我。 linux當中的函數指針,那是鑼鼓喧天鞭炮齊鳴紅旗招展人山人海啊~~;旧现灰墙Y構體,里面都必有一個(gè)函數指針,而且是一層嵌套一層地層層抽象上去,還有一堆令人頭皮發(fā)麻的void *無(wú)類(lèi)型指針,指針和變量齊飛,代碼共數據一色。所以,高薪不是沒(méi)有依據的。隨著(zhù)android的迅猛發(fā)展,大家接觸linux內核的機會(huì )也會(huì )越來(lái)越多。 當然多數人沒(méi)那么好運的,我們說(shuō)點(diǎn)實(shí)際點(diǎn)的,M0/M3平臺。這個(gè)平臺是很適用函數指針的,因為它是壓棧式的編譯方式。它最廣泛的應用是回調函數,就我個(gè)人體會(huì )來(lái)講,回調函數主要是為了分層清晰和模塊化而存在的。我底層想傳遞消息給頂層,但又不好直接調用頂層函數,于是就用函數指針這種暗度陳倉的方式。有人說(shuō),直接調用不就得了,搞什么虛文。問(wèn)題是頂層隨時(shí)可能換,函數名也會(huì )變,到時(shí)候移植起來(lái)發(fā)現,頂層和底層盤(pán)根錯節,相互依賴(lài),那是很痛苦的。頂層對底層說(shuō),小兄弟,這個(gè)事情你先做,有什么情況你就打電話(huà)給我,剩下的我來(lái)處理。底層含著(zhù)眼淚對頂層說(shuō),哥,你別說(shuō)了,你還是先把電話(huà)號碼給我吧,您干嘛老換號碼啊。這個(gè)記錄電話(huà)的媒介,就是回調函數指針。 回調之妙,食髓知味。 夜了,閃人先,期待本文1.1版吧,呵呵 哎,自己回頭看了一遍,內容冗余,表達轉折突兀,不夠圓潤,容我再細細梳理一翻... |