吴忠躺衫网络科技有限公司

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

真刀真槍模塊化(2.5)— 掩碼結構體

電子設計 ? 來源:電子設計 ? 作者:電子設計 ? 2020-12-14 21:00 ? 次閱讀
作者: GorgonMeducer 傻孩子
首發:裸機思維


【說在前面的話】


在本系列的前一篇文章《真刀真槍模塊化(2)——圖解Service模型》中,我們介紹了一種模塊化封裝的模型——Service模型。該模型的設計理念實際上服務于一個叫做“黑盒子哲學”的設計思維,其核心思想是:

  • 將模塊視作一個黑盒子:模塊的設計者不用向外透露黑盒子的實現細節;同時模塊的使用者也無法看到黑盒子的內部
  • 模塊的設計者和模塊的使用者完全通過“接口”來進行約定和溝通。這里所有的接口約定都是通過接口頭文件來進行描述和傳遞的。
  • 接口(及接口頭文件)遵循“最小信息公開原則”,即,任何跟使用模塊所提供的服務無關的、或者非必要(可有可無)信息都應該從接口頭文件中刪除。

實踐中,要想實現黑盒子,我們實際上要完成兩大任務:

  1. 如何隱藏模塊的實現,或者說隱藏源代碼;
  2. 接口頭文件中數據結構的保護,或者說如何阻止用戶繞開模塊所提供的API而直接訪問關鍵結構體的內部(私有)成員

對于第一條來說,我們只需要把模塊編譯成library,連同接口頭文件一起提供給客戶使用就可以做到;而對于第二條要想實現起來卻并非那么簡單——雖然我們常常說C語言可以通過結構體來模擬類的概念,但它卻無法像C++的類那樣提供對私有(private)和受保護(protected)成員的隱藏。換句話說,在實踐“最小信息公開原則”的時候,如果用戶調用服務的時候,確實需要用到結構體(這個結構體是最小信息),如何防止結構體的定義信息被“非法使用”,就成了一個切實的難題。
為了讓后續的討論更為清晰,我們不妨具體的定義一下我們的任務:

  • 只允許用戶使用結構體的大小對齊信息——這樣用戶可以自由的定義變量,或是通過malloc這樣的函數進行動態分配;
  • 以某種“通過實際手段強制了的君子協定”的形式——僅在語法層面——阻止用戶直接訪問結構體的成員。

要想同時做到以上兩點,離不開今天索要介紹的主角:掩碼結構體(Masked Structure)。
【什么是掩碼結構體】


要想理解掩碼結構體,拋開復雜和抽象的文字描述,我們不妨來看一個具體的例子:假設我們做了一個字節隊列的模塊,其中最核心的結構體 byte/_queue/_t 的定義如下:

typedef struct byte_queue_t byte_queue_t;

針對這一結構體(或者叫類)我們提供一系列API(或者叫類的方法),比如:

typedef struct byte_queue_cfg_t {

為了保證模塊的正常工作,防止運行期間,用戶為了自身的便利,直接”外科手術式的“訪問 byte/_queue/_t 的成員導致不必要的問題(比如用戶說:我知道你遵循的是最小信息公開原則,也就是說,只要你放了結構體在接口頭文件里,我當然理解為我可以任意使用咯?),我們想將整個 byte/_queue/_t 都保護起來——這就好比,我們試圖引入一個“蒙版”,遮住結構體的成員信息然后在客戶的耳邊念起魔咒:
你什么都看不到,你看到了也沒法用……
你什么都看不到,你看到了也沒法用……
你什么都看不到,你看到了也沒法用……

...

要想實現這樣的“蒙版效果”其實并不困難,只需要知道要屏蔽的部分實際占用memory的大小,再根據這一大小來定義數組即可,因此,我們可以修改對應的定義為:

typedef struct byte_queue_t byte_queue_t;

這里,我們實際上是給原來的類型重命名為/_/_byte/_queue/_t,并建立了一個內部只使用數組來“濫竽充數”的替身——也就是我們所說的掩碼結構體。

如果你看過我之前的文章《漫談C變量——對齊(3)》,你會注意到,上述替身實際上丟失了結構體 /_/_byte/_queue/_t 的對齊信息——容易注意到 struct /_/_byte/_queue/_t 的結構體整體是對齊到 4 字節的,而掩碼結構體中數組chMask本身是對齊到字節的——這會導致當用戶使用掩碼結構體來定義變量時,由編譯器分配的空間可能無法滿足原結構體對對齊的要求,造成非對齊訪問——輕則性能下降,重則hardfault。

要解決這一問題也并不復雜,只需要借助GCC擴展的運算符 /_/_alignof/_/_() 提取目標類型的對齊信息,再使用/_/_attribute/_/_((aligned())) 來設置掩碼數組的對齊要求就可以了:

typedef struct byte_queue_t byte_queue_t;

至此,掩碼結構體 byte/_queue/_t 擁有了和原本的結構體 struct /_/_byte/_queue/_t 一樣的尺寸和對齊;同時還在“語法”層面阻止了用戶直接訪問結構體成員的可能(當然,這也只能防君子不防小人),我們原本設立的兩個目標都已成功達成。然而,聰明的你會在腦海里浮現出一個疑問——要想掩碼結構體能正常工作,上述信息都必須放置到接口頭文件中,難道用戶是傻子,看不到結構體 /_/_byte/_queue/_t 么?

借助宏的力量,我們可以成功的隱藏住 struct /_/_byte/_queue/_t 的存在。


下面的宏只是為了演示一種簡單的實現方法,暫時的打消你的疑慮,而實際在后面我們將要介紹的PLOOC模板中所使用的技法則更為復雜。由于本文只是著重于實際工程實踐中如何簡單的應用掩碼結構體,而不在于介紹復雜的宏技巧,因此我們將不在討論 PLOOC的實現細節。


#definedeclare_class(__name)     /

借助上述宏,我們可以將接口頭文件 byte/_queue.h 中代碼簡化為:

...

而模塊源代碼中,則可以使用 class/_internal() 來獲取原本的結構體類型:

...

【如何使用PLOOC來簡化開發】


PLOOCProtected Low-overheadObject-Oriented programming with ANSI-C的英文縮寫,意為:為(類)提供保護的、低開銷的、面向對象C語言開發。它是我在 Github 上的一個開源項目(https://github.com/GorgonMedu...)。PLOOC 是目前已知唯一使用掩碼結構體對私有(private)和受保護(protected)的成員提供隱藏的OOPC模板;除此以外,通過幾近于0的額外資源消耗來實現面向對象封裝特性,也是PLOOC的一大賣點。

雖然PLOOC自帶的 MDK 例子工程演示了常見的面向對象特性,但處于時間問題,仍然沒有來得及提供一份簡單直接的手把手使用教程。這里我們仍然以 byte/_queue/_t 為例,為大家介紹一下如何在自己的工程中部署 PLOOC,并應用到 service模型中。

準備階段

  • 從Github上下載最新的 release 版本。

  • 解壓縮后重命名目錄為 PLOOC,并復制到你的目標工程中

  • 在你的工程中添加對PLOOC目錄的引用

  • 在工程配置中打開對 C99 的支持,如果可能,直接開啟 C11和GNU擴展的支持:

  • 如果你使用的是 gcc, clang 或是 arm compiler 6,你還需要打開對微軟擴展的支持(-fms-extensions)并屏蔽一些惱人且無害的 warning:
-fms-extensions -Wno-microsoft-anon-tag -Wno-empty-body


NOTE:如果你使用的是 arm compiler 6,在開啟微軟擴展以后,還需要額外定義一個宏 /_MSC/_VER 來避免底層庫中的一些不必要的編譯錯誤。
至此,我們就完成了 PLOOC 在你工程中的部署。

如何在模塊中部署

仍以 byte/_queue 模塊為例,假設你已經根據 service 模型構建好了目錄結構:

  • 打開接口頭文件 byte/_queue.h 并在靠近結構體定義的地方其中添加以下內容:
/*! /NOTE: Make sure #include "plooc_class.h" is close to the class definition 

這里,我們定義了兩個很重要的宏 /_/_BYTE/_QUEUE/_CLASS/_IMPLEMENT/_/_BYTE/_QUEUE/_CLASS/_INHERIT/_/_。容易看出,他們分別是根據

__<模塊名稱>_CLASS_IMPLEMENT

__<模塊名稱>_CLASS_INHERIT__

的形式改寫而成的。前者的作用是給 C 源代碼標記“我是這個類的實現,我是類的主人”的身份用的;后者的作用是給 C代碼標記“我是派生類的實現,我派生自基類”。具體使用方法,后面會具體介紹。
需要特別強調的是,一定不要忘記在接口頭文件的尾部將這兩個宏都undef掉

...
  • 在 byte/_queue.h 里定義目標類:
//! /name class byte_queue_t

值得注意的是,這里我們用 private/_member()protected/_member()的形式規定了成員變量的屬性:其中private的成員是只有類的主人自己可見;而 protected的成員是類的主人以及派生類都可見。如果你想指定某些成員是公共可見的,則可以使用 public/_member()

  • 打開 byte/_queue.c,在文件的最開始通過定義宏 /_/_BYTE/_QUEUE/_CLASS/_IMPLEMENT 來標記自己“類主人”的身份,當然,別忘記包含自己的接口頭文件:
#define __BYTE_QUEUE_CLASS_IMPLEMENT
  • 在 byte/_queue.c 中,如果某個函數(類的方法)試圖訪問類的成員,則應該首先借助 class/_internal() 來“脫下馬甲”。方法跟前文一樣,這里就不再贅述。

完整的例子在 PLOOC 的example目錄下:諸如派生類應該如何處理函數重載應該如何實現等等問題,大家可以打開MDK的例子工程后“細品”。

【后記】


掩碼結構體是一種全新的方法,可以在語法層面上限制模塊的使用者對關鍵的結構體(類)成員的訪問。相比大家熟悉的“不完全類型”,掩碼結構體攜帶了足夠的信息(大小信息和對齊信息),從而允許模塊的使用者自由的定義變量或是動態分配,這與“不完全類型”必須依賴動態分配的缺點形成了鮮明的對比。
曾幾何時,掩碼結構體還有“模塊的.c不能包含模塊的接口頭文件” 這樣的限定,在最新的PLOOC中,這一問題已經得到了徹底的解決——再也不用擔心 ".c" 和 ".h" 中的類型描述不一致導致的運行時錯誤。
最后,需要強調一下,對 service 模型來說,掩碼結構體,或者說PLOOC的使用只是“錦上添花”——并非必須。讀者完全可以根據自己的喜好來決定模塊的實現方式。如果你喜歡或者對PLOOC使用有什么建議,歡迎在 github上提交你的issue。


審核編輯 黃昊宇

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 深度學習
    +關注

    關注

    73

    文章

    5516

    瀏覽量

    121553
收藏 人收藏

    評論

    相關推薦

    模塊化結構與同容量分立器件結構的不同

    模塊化結構提高了產品的密集性、安全性和可靠性,同時也可降低裝置的生產成本,縮短新產品進入市場的周期,提高企業的市場競爭力。由于電路的聯線已在模塊內部完成,因此,縮短了元器件之間的連線,可實現優化布線
    發表于 09-09 09:15

    模塊化程序設計

    模塊化程序設計思想,單片機c語言的模塊化設計,方便移植,將程序封裝備用。
    發表于 03-22 15:29 ?9次下載

    AMD二代霄龍迎來歷史上的最佳機遇

    AMD Ryzen銳龍這兩年讓微處理器乃至是整個PC領域煥發了新的勃勃生機,喜聞樂見的真刀真槍激烈競爭重現江湖,是整個行業以及所有消費者的福音。
    發表于 07-02 15:17 ?602次閱讀

    愛立信:5G提前開花結果,中國市場期待真正收獲

    在5G真刀真槍的開啟商用元年之后,百年老店也持續露出復蘇態勢。
    的頭像 發表于 07-22 11:26 ?2040次閱讀

    西門子s7-300模塊化結構及組成部分

    基本的模塊化硬件結構結構包括機架、電源、處理器CPU、輸入輸出I/O模塊、編程或通訊用接口,圖1表示了一個模塊化控制器是如何由
    的頭像 發表于 02-22 06:56 ?1.9w次閱讀
    西門子s7-300<b class='flag-5'>模塊化</b><b class='flag-5'>結構</b>及組成部分

    模塊化UPS電源的分布結構

    分布式是早期模塊化UPS經常使用的一種架構。此類模塊化UPS系統層面上等價于數臺獨立的UPS直接并聯,其功率模塊利用小型UPS改造而成,可自主獨立工作。
    發表于 05-29 10:25 ?1555次閱讀

    真刀真槍模塊化(2)—圖解Service模型

    作者: GorgonMeducer 傻孩子首發:裸機思維 【說在前面的話】在前面一篇文章《真刀真槍模塊化(1)——一本糊涂賬》中,我們討論了:在工...
    的頭像 發表于 12-14 22:38 ?543次閱讀

    FPGA模塊化設計與AlteraHardCopy結構化ASIC

    本文檔的主要內容詳細介紹的是FPGA模塊化設計與AlteraHardCopy結構化ASIC。
    發表于 01-20 17:03 ?6次下載
    FPGA<b class='flag-5'>模塊化</b>設計與AlteraHardCopy<b class='flag-5'>結構化</b>ASIC

    華為模塊化數據中心解決方案顯著提升模塊化建筑結構的抗震性能

    近日,華為聯合同濟大學申報的預制模塊化數據中心解決方案磐石架構技術——箱式模塊化數據中心建筑結構設計技術與設計軟件開發技術,榮獲中國建筑學會科技進步獎。這是繼2020年,該技術獲上海市建筑學會科技進步獎后,再次實現“跨界出圈”,
    的頭像 發表于 11-20 14:15 ?3185次閱讀

    真刀真槍模塊化(3.5)——騷操作?不!這才是正統

    首發:裸機思維作者: GorgonMeducer 傻孩子【你可曾懷疑過?】C語言寫多了,或多或少會聽說一些“上古傳下來”的教條,比如:include 語...
    發表于 01-25 18:28 ?0次下載
    <b class='flag-5'>真刀真槍</b><b class='flag-5'>模塊化</b>(3.5)——騷操作?不!這才是正統

    真刀真槍模塊化(3)—— 層次框架初探

    作者: GorgonMeducer 傻孩子首發:裸機思維(圖片來自網絡,侵刪) 【說在前面的話】在本系列的前面幾篇文章中,我們依次討論了如下的幾...
    發表于 01-25 19:44 ?0次下載
    <b class='flag-5'>真刀真槍</b><b class='flag-5'>模塊化</b>(3)—— 層次框架初探

    真刀真槍模塊化(1)——一本糊涂賬

    對很多人來,嵌入式軟件開發過程中?模塊化(Modularization)是一個海市蜃樓、是一個書面詞匯、是一個過氣的時尚——模塊化似乎從未真正的...
    發表于 01-26 19:33 ?0次下載
    <b class='flag-5'>真刀真槍</b><b class='flag-5'>模塊化</b>(1)——一本糊涂賬

    什么是模塊化自動

    什么是模塊化自動
    的頭像 發表于 03-10 16:29 ?2932次閱讀
    什么是<b class='flag-5'>模塊化</b>自動<b class='flag-5'>化</b>?

    歐姆龍模塊化編程的使用技巧

    【導讀】在平常使用歐姆龍SysmacStudio 編程時,有新建大量的結構和全局變量,若不分類進行模塊化,會造成查找不方便,下面分享的就是對全局變量和數據類型進行模塊分類,方便查找,
    的頭像 發表于 03-17 17:45 ?2103次閱讀

    PLC模塊化結構化編程實例

    模塊化編程中OB1起著主程序的作用,FC或FB控制著不同的過程任務,相當于主循環程序的子程序。模塊化編程中被調用塊不向調用塊返回數據。
    的頭像 發表于 07-10 14:42 ?1131次閱讀
    PLC<b class='flag-5'>模塊化</b>和<b class='flag-5'>結構化</b>編程實例
    百家乐官网娱乐官网| 金牌百家乐官网的玩法技巧和规则 | 正规棋牌游戏| 菲彩国际| 百家乐官网大转轮| 开平市| 正品百家乐官网游戏| 百家乐桌子| 利博国际网址| 百家乐官网投注方法多不多| 百家乐必胜绝技| 大发888亚洲| 菲律宾百家乐官网的说法| 百家乐官网技巧打| 至尊百家乐娱乐| 百家博彩网| 博彩百家乐官网的玩法技巧和规则| 百家乐太阳城| 平博娱乐| 百家乐官网博彩平| 大都会百家乐的玩法技巧和规则| 乳山市| 百家乐是真的吗| 大发888真钱游戏下载到桌面| 加州百家乐官网娱乐城| 百家乐庄家出千内幕| 鸿博娱乐场| 伟易博百家乐官网娱乐城 | 百家乐网上真钱娱乐场| 邹城市| 百家乐视频游戏金币| 蓝盾网上娱乐| 利记百家乐现金网| 能赚钱的棋牌游戏| 喜达百家乐官网的玩法技巧和规则 | 百家乐官网娱乐城新澳博| 百家乐赌博平台| 网上真钱娱乐| 澳门百家乐现场游戏| 菲彩线上娱乐| 免费百家乐官网预测软件|