我是老溫,一名熱愛學(xué)習(xí)的嵌入式工程師,關(guān)注我,一起變得更加優(yōu)秀!
前面的一系列技術(shù)文章,我們都曾多次充分說明了,在設(shè)計(jì)業(yè)務(wù)邏輯復(fù)雜的嵌入式軟件時(shí),最好以面向?qū)ο笞鳛榛镜脑O(shè)計(jì)思想,對(duì)各個(gè)功能模塊盡可能地做好封裝與解耦。關(guān)于嵌入式 C 語言面向?qū)ο笤O(shè)計(jì)的文章,可以點(diǎn)擊以下鏈接進(jìn)行回顧:
基于狀態(tài)機(jī)和面向?qū)ο蟮乃枷?,設(shè)計(jì)一個(gè)通用的按鍵檢測(cè)模塊。
基于面向?qū)ο蠛秃唵喂S模式,設(shè)計(jì)一個(gè)通用的 LED 顯示模塊。
面向?qū)ο笫且环N基本的設(shè)計(jì)思想,與所采用的編程語言基本無關(guān)(如果非要杠匯編和二進(jìn)制,那就是你對(duì)),一個(gè)反面的例子就是,很多人在初學(xué)C++的時(shí)候,即便C++里面集成了很多面向?qū)ο笤O(shè)計(jì)的語法糖,但初學(xué)者依然會(huì)很容易把“類”當(dāng)作結(jié)構(gòu)體使用。
面向?qū)ο蟮幕境霭l(fā)點(diǎn)是:把“數(shù)據(jù)屬性”與“數(shù)據(jù)屬性的處理方法”都封裝在一起。而我們?cè)谑褂?C 語言進(jìn)行嵌入式功能模塊設(shè)計(jì)的時(shí)候,因?yàn)镃語言并不具備C++語言的語法糖,所以通常都會(huì)使用結(jié)構(gòu)體的方式來模擬類的設(shè)計(jì)。
因此,我們?cè)谑褂肙OC(Object-Oriented C Programming with ANSI -C)技術(shù)的時(shí)候,通常都會(huì)面臨以下問題:
“嗯,我們可以使用結(jié)構(gòu)體來模擬類,把所有數(shù)據(jù)變量和函數(shù)指針都放在結(jié)構(gòu)體里面進(jìn)行封裝,并且把這個(gè)結(jié)構(gòu)體放在接口頭文件里面,那么問題來了,結(jié)構(gòu)體里面的成員都是public的(語法層面可以直接使用),但某些數(shù)據(jù)變量卻是private屬性(不允許被模塊外部直接調(diào)用)”
那么,應(yīng)該如何解決這個(gè)問題呢?
在我以往編寫的 C 語言面向?qū)ο笪恼吕锩?,示例代碼的接口頭文件,通常都伴隨著這個(gè)“直接且尖銳”的問題,而通過編碼和模塊引用規(guī)范這一系列的“君子協(xié)定”,往往只能起到“防君子而不能防小人”的作用。
直到最近,我看了傻孩子大佬(公眾號(hào):裸機(jī)思維)的一系列文章才知道,原來C語言里面有一種技法,掩碼結(jié)構(gòu)體(Masked Structure),可以為結(jié)構(gòu)體里面的private屬性變量蓋上一層蒙版,模塊使用者即使看到了結(jié)構(gòu)體的私有數(shù)據(jù)變量,也不能對(duì)其進(jìn)行外部直接訪問調(diào)用。
在通用的單片機(jī)按鍵檢測(cè)模塊這篇文章里面,對(duì)于模塊的接口頭文件 key_module.h,里面兩個(gè)最主要的結(jié)構(gòu)體,key_t和key_manager_t,其內(nèi)部大量暴露了模塊的私有參數(shù)變量,如下圖所示。
模塊使用者如果想通過某些簡單直接粗暴的方式,去修改模塊的各個(gè)屬性參數(shù),是一件輕而易舉(技術(shù)上也是合情合理)的事情,因?yàn)楦鶕?jù)接口頭文件的最小信息公開原則,放在頭文件的信息內(nèi)容,難道不是公開且供大家放心使用的么?~
(此刻,作者我,無言以對(duì)。。。)
鑒于key_module.h接口頭文件顯現(xiàn)出來的設(shè)計(jì)不足,我們可以使用掩碼結(jié)構(gòu)體對(duì)其進(jìn)行改進(jìn),例如,對(duì)于原來的key_t結(jié)構(gòu)體,我們可以把私有不公開的成員,放在struct __key里面,然后 key_t 結(jié)構(gòu)體則改進(jìn)成如下圖所示的方式。
然而,這種改進(jìn)并未能在真正意義上掩蓋住私有成員(struct __key的信息依然表露無遺),因此,我們參考“真刀真槍模塊化(2.5)--君子協(xié)定”這篇文章,可以通過宏定義技法,把私有成員結(jié)構(gòu)體的信息,真正隱藏起來,如下圖所示。
使用以上宏定義,那么我們可以繼續(xù)對(duì)struct __key結(jié)構(gòu)體作出進(jìn)一步的改進(jìn),把結(jié)構(gòu)體的聲明和成員定義,都交給了預(yù)編譯宏進(jìn)行處理,具體代碼如下圖所示。
當(dāng)我們需要提取結(jié)構(gòu)體成員進(jìn)行使用的時(shí)候,可以使用CLASS_INTERNAL宏,該宏展開后是一種強(qiáng)制類型轉(zhuǎn)換,目的是可以通過已知類型的結(jié)構(gòu)體變量,來顯式調(diào)用結(jié)構(gòu)體成員,使用方式如下圖所示。
以上,就是使用掩碼結(jié)構(gòu)體技法對(duì)單片機(jī)按鍵模塊的簡單改進(jìn)(以上截圖多數(shù)為偽代碼,提供一種思路),在實(shí)際的工程項(xiàng)目里面,推薦直接使用PLOOC,這個(gè)開源項(xiàng)目已經(jīng)很完美地為C語言面向?qū)ο箝_發(fā)提供了必要的OOPC模板。
感謝閱讀。