void指針進階用法你了解嗎盅惜?

[導(dǎo)讀] 要比較靈活的使用C語言實現(xiàn)一些高層級的框架時趋翻,需要掌握一些進階編程技巧酿箭,這篇來談?wù)剉oid指針的一些妙用污它。測試環(huán)境采用 IAR for ARM 8.40.1

什么是void指針

void指針一般被稱為通用指針或叫泛指針葡兑。它是C語言關(guān)于純粹地址的一種約定没咙。當某個指針是void型指針時,所指向的對象不屬于任何類型职辨。因為void指針不屬于任何類型盗蟆,則不可以對其進行算術(shù)運算,比如自增舒裤,編譯器不知道其自增需要增加多少喳资。比如char *型指針,自增一定是指針指向的地址加1腾供,short *型指針自增仆邓,則偏移2鲜滩。

**在C/C++中,在任意時刻都可以使用其它類型指針來代替void指針节值,或者用void指針來代替其他類型指針徙硅。**由這些特性就可以衍生出很多比較有用的技巧。指針的本質(zhì)搞疗,是其值為一個地址嗓蘑,那么延伸一下:

當使用關(guān)鍵字void聲明指針變量時,它將成為通用指針變量匿乃。 任何數(shù)據(jù)類型(char桩皿,int,float等)的任何變量的地址都可以賦值給void指針變量幢炸。

對指針變量的解引用泄隔,使用間接運算符*達到目的。 但是在使用空指針的情況下宛徊,需要轉(zhuǎn)換指針變量以解引用佛嬉。 這是因為空指針沒有與之關(guān)聯(lián)的數(shù)據(jù)類型。 編譯器無法知道void指針指向的數(shù)據(jù)類型闸天。 因此暖呕,要獲取由void指針指向的數(shù)據(jù),需要使用在void指針位置內(nèi)保存的正確類型的數(shù)據(jù)進行類型轉(zhuǎn)換号枕。

對于空指針的解引用缰揪,你如不信,就來看看栗子:


看到了吧葱淳,直接解引用編譯不過,因為編譯器蒙了抛姑。

但須注意的是:

不同的編譯器對void指針處理是不一樣的赞厕,如IAR,ANSI C,VC對上述都將出錯定硝,而GNU指定“void”的算法操作與“char”一致皿桑,因此上述寫法在GNU則可以編譯

所以做個類型轉(zhuǎn)換,修正如下:


void型指針解引用須做類型指定蔬啡。

類型轉(zhuǎn)換的時候須注意類型匹配诲侮。

另外,**如果函數(shù)類型可以是任意類型的指針箱蟆,則需將其參數(shù)定義為void ***,例如string.h中關(guān)于內(nèi)存操作的函數(shù)集:

__EFF_NENW1NW2???__ATTRIBUTESintmemcmp(constvoid*,constvoid*,

size_t);

__EFF_NENR1NW2R1?__DEPREC_ATTRSvoid*memcpy(void*_Restrict,

constvoid*_Restrict,

size_t);

__EFF_NENR1NW2R1?__DEPREC_ATTRSvoid*memmove(void*,constvoid*,

size_t);

__EFF_NENR1R1????__DEPREC_ATTRSvoid*memset(void*,int,size_t);

非易失存儲管理應(yīng)用

在單片機開發(fā)中沟绪,往往需要實現(xiàn)數(shù)據(jù)的非易失存儲。所謂非易失存儲空猜,就是數(shù)據(jù)改寫后在掉電后仍然能保持绽慈。哪些是非易失存儲介質(zhì)呢恨旱?比如EEPROM,FLASH等都屬于非易失存儲介質(zhì)。

比如一個產(chǎn)品里面有很多各種各樣的參數(shù)坝疼,且分布在各個子系統(tǒng)文件中搜贤。舉個栗子:

/*模塊A中有這樣一個結(jié)構(gòu)體需要非易失存儲*/

typedefstruct_t_paras{

intlanguage;/*語言種類*/

charSN[20];/*產(chǎn)品序列號*/

}T_PARAS;

T_PARAS?sysParas;

/*模塊B中有這樣一個結(jié)構(gòu)體需要非易失存儲*/

typedefstruct_t_pid{

floatkp;

floatki;

floatkd;

floatT;

}T_PID;

T_PID?pidParas;

面對這樣一個需求,要實現(xiàn)非易失存儲钝凶,我在將底層的EEPROM/FLASH讀寫函數(shù)實現(xiàn)的基礎(chǔ)上仪芒,將上述應(yīng)用數(shù)據(jù)按照一定順序存儲管理。那么更為理想的方式是什么呢耕陷?設(shè)計一個模塊專門負責存儲非易失數(shù)據(jù)掂名。比如:

typedefstruct_t_nv_layout{

void*?pElement;/*參數(shù)地址*/

intlength;/*參數(shù)長度*/

}T_NV_LAYOUT;

/*參數(shù)映射表*/

T_NV_LAYOUT?nvLayout[]={

{&sysParas,sizeof(T_PARAS)},/*參數(shù)映射記錄*/

{&pidParas,sizeof(T_PID)},

...

};

/*參數(shù)映射表記錄條數(shù)*/

#defineNV_RECORD_NUMBER??(sizeof(nvLayout)/sizeof(T_NV_LAYOUT))

voidnv_load(T_NV_LAYOUT?*pLayout,intnvAddr,intnumber);

voidnv_store(T_NV_LAYOUT?*pLayout,intnvAddr,intnumber);

將上述設(shè)計思想,利用UML描述一下:


在上述基礎(chǔ)上啃炸,我們只需要設(shè)計硬件層抽象铆隘,即可設(shè)計出一個可行的、比較通用的NV管理子系統(tǒng)南用,這樣設(shè)計出的子系統(tǒng)忽略了業(yè)務(wù)數(shù)據(jù)膀钠,僅僅將其處理為數(shù)據(jù),并不關(guān)心其業(yè)務(wù)意義裹虫。實現(xiàn)了業(yè)務(wù)邏輯與后臺的隔離解耦肿嘲。做到了通用性。這里就比較巧妙的利用了void *指針的特性筑公。如果對于該設(shè)計思想雳窟,在進一步延伸,將底層的抽象在做一層封裝匣屡,將更細節(jié)的底層實現(xiàn)細節(jié)隔離抽象封救,比如:

抽象I2C/SPI EEPROM,將其對上層的調(diào)用接口統(tǒng)一捣作,那么如果你的系統(tǒng)原本是存儲在I2C EEPROM中誉结,現(xiàn)在做一個新項目,你需要使用另外一種SPI接口的EEPROM券躁,則只需要實現(xiàn)相應(yīng)的底層處理函數(shù)即可惩坑。

將存儲介質(zhì)抽象,比如是EEPROM/DATA FLASH等...

....

那么怎么做到底層抽象呢也拜,我們可以利用函數(shù)指針定義統(tǒng)一的接口以舒,具體部署時,只需要將實現(xiàn)函數(shù)的指針賦值給對應(yīng)的函數(shù)指針即可慢哈,這樣就做到了接口的抽象統(tǒng)一蔓钟。其實這就是驅(qū)動模型的一個簡易雛形。


總結(jié)一下

這篇文章引入了一些編程思想岸军,對于單片機/嵌入式進階編程比較有用:

利用void *指針奋刽,將業(yè)務(wù)數(shù)據(jù)與底層存儲實現(xiàn)了抽象解耦

利用分層抽象實現(xiàn)了代碼具有良好的可移植性

利用函數(shù)指針實現(xiàn)了C++等高級語言的虛函數(shù)定義接口的思想

統(tǒng)一接口底層實現(xiàn)抽象瓦侮,實現(xiàn)了驅(qū)動分層的思想

void *指針由這個例子,可以延伸出很多類似的應(yīng)用

啟示:一些語言細節(jié)如果深入了解其背后的機理佣谐,可以得到很多比較巧妙的應(yīng)用肚吏。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
禁止轉(zhuǎn)載,如需轉(zhuǎn)載請通過簡信或評論聯(lián)系作者狭魂。
  • 序言:七十年代末罚攀,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子雌澄,更是在濱河造成了極大的恐慌斋泄,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,576評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件镐牺,死亡現(xiàn)場離奇詭異炫掐,居然都是意外死亡,警方通過查閱死者的電腦和手機睬涧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,515評論 3 399
  • 文/潘曉璐 我一進店門募胃,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人畦浓,你說我怎么就攤上這事痹束。” “怎么了讶请?”我有些...
    開封第一講書人閱讀 168,017評論 0 360
  • 文/不壞的土叔 我叫張陵祷嘶,是天一觀的道長。 經(jīng)常有香客問我夺溢,道長论巍,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,626評論 1 296
  • 正文 為了忘掉前任风响,我火速辦了婚禮环壤,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘钞诡。我一直安慰自己,他們只是感情好湃崩,可當我...
    茶點故事閱讀 68,625評論 6 397
  • 文/花漫 我一把揭開白布荧降。 她就那樣靜靜地躺著,像睡著了一般攒读。 火紅的嫁衣襯著肌膚如雪朵诫。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,255評論 1 308
  • 那天薄扁,我揣著相機與錄音剪返,去河邊找鬼废累。 笑死,一個胖子當著我的面吹牛脱盲,可吹牛的內(nèi)容都是我干的邑滨。 我是一名探鬼主播,決...
    沈念sama閱讀 40,825評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼钱反,長吁一口氣:“原來是場噩夢啊……” “哼掖看!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起面哥,我...
    開封第一講書人閱讀 39,729評論 0 276
  • 序言:老撾萬榮一對情侶失蹤哎壳,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后尚卫,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體归榕,經(jīng)...
    沈念sama閱讀 46,271評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,363評論 3 340
  • 正文 我和宋清朗相戀三年吱涉,在試婚紗的時候發(fā)現(xiàn)自己被綠了刹泄。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,498評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡邑飒,死狀恐怖循签,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情疙咸,我是刑警寧澤县匠,帶...
    沈念sama閱讀 36,183評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站撒轮,受9級特大地震影響乞旦,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜题山,卻給世界環(huán)境...
    茶點故事閱讀 41,867評論 3 333
  • 文/蒙蒙 一兰粉、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧顶瞳,春花似錦玖姑、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,338評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至符喝,卻和暖如春闪彼,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背协饲。 一陣腳步聲響...
    開封第一講書人閱讀 33,458評論 1 272
  • 我被黑心中介騙來泰國打工畏腕, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留缴川,地道東北人。 一個月前我還...
    沈念sama閱讀 48,906評論 3 376
  • 正文 我出身青樓描馅,卻偏偏與公主長得像把夸,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子流昏,可洞房花燭夜當晚...
    茶點故事閱讀 45,507評論 2 359