亚洲免费av电影一区二区三区,日韩爱爱视频,51精品视频一区二区三区,91视频爱爱,日韩欧美在线播放视频,中文字幕少妇AV,亚洲电影中文字幕,久久久久亚洲av成人网址,久久综合视频网站,国产在线不卡免费播放

        ?

        適用于C語言的對象模型的研究與實現(xiàn)

        2013-07-03 00:45:10孟繁超葉會英
        計算機工程與設計 2013年4期
        關鍵詞:定義結構模型

        孟繁超,葉會英

        (鄭州大學 信息工程學院,河南 鄭州 450001)

        0 引 言

        隨著面向?qū)ο蟮木幊趟枷耄╫bject oriented programming)的推廣與普及,C 語言在數(shù)據(jù)封裝上的缺點也日益凸顯。為了解決這一問題,Bjarne Stroustrup于20世紀80年代發(fā)明了C++語言。C++語言在不斷發(fā)展和改進的同時,由于引入了過多的特性,其依舊存在語法過于冗雜,標準不統(tǒng)一等問題,這也使得其在一些硬件受限設備中以及系統(tǒng)級編程中并不適用。

        雖然C語言本身對面向?qū)ο蟮奶匦灾С钟邢?,但這并不影響面向?qū)ο蟮乃枷朐贑 語言中的應用。實際中,可借助代碼生成工具或代碼擴展工具配合一定的代碼規(guī)范或設計模式進行模擬,從而提高C 程序的可重用性。在桌面Linux系統(tǒng)中廣泛使用的GNOME 界面系統(tǒng)是C 語言應用面向?qū)ο笏枷氲囊粋€代表,其底層的GObject庫提供了一套完善的面向?qū)ο蟮念愋拖到y(tǒng)。而早在早在C++創(chuàng)立之初,Bjarne Stroustrup也曾嘗試過用類似的方法對C語言進行改造[1-2]。

        在C89標準[3]中增加了泛型指針以及C99標準[4]中增加可變宏參數(shù)、結構體初始化等特性的支持之后,C 語言的元編程能力得以進一步的加強。合理的利用現(xiàn)代編譯器的這些特性,配合專門設計的對象模型,可以將部分C++在編譯時完成的動作讓C 語言在運行時來進行,進而可以在保證易用性的同時為C 語言增加對封裝、繼承和多態(tài)等特性的支持。實際中,利用托管于Google Code的OOCGCC項目[5]中的代碼,可以完成對面向?qū)ο笏枷氲哪M,且能夠很好的適用于AVR,STM32等一些嵌入式平臺。

        1 對象模型的內(nèi)存分布

        1.1 C++的對象模型

        無論何種編程語言,只要其具備面向?qū)ο蟮奶匦?,都需要專門為其設計特定的對象模型。為了方便說明,這里以一個C++類為例引出幾種常規(guī)的對象模型的設計。

        在C++中,類的成員有兩種內(nèi)存屬性,靜態(tài)的(static)和非靜態(tài)的(non-static)。而類的方法則有3種內(nèi)存屬性,靜態(tài)的(static),非靜態(tài)的(non-static)以及虛擬的(virtual)。

        現(xiàn)假定有一用C++定義的類如圖1所示。

        圖1 C++類示例

        而圖1例子中涵蓋了這些不同屬性的方法和成員,其內(nèi)存分布[6]情況如圖2所示。

        圖2 C++內(nèi)存模型

        C++的對象模型中有相當一部分內(nèi)存空間是在編譯時獨立分配的,同時如果某個類有以virtual關鍵字聲明的方法(圖1中為虛析構方法)則該模型會具備獨立的虛表結構,且在虛表結構中還擁有一個提供RTTI(RunTime type information)特性的類型信息區(qū)域。

        借助于編譯器,C++可以保證使用時代碼的簡潔性,但如果要使用C語言直接去實現(xiàn)這樣的對象模型,因為要將編譯時的工作轉(zhuǎn)移至運行時來做,必然會引入大量額外的附加代碼。為此,必須對該模型進行改良,以適應C 語言的某些特性。

        1.2 適用于C語言的對象模型

        用C語言去模擬面向?qū)ο蟮奶匦杂泻芏喾绞?,引言中提及的GObject庫雖然模擬了很多面向?qū)ο蟮奶匦?,但這種模擬因為引入了過多的特性而在實際使用時顯得非常繁瑣[7-8]。為了在功能和易用性之間尋求一種平衡,OOCGCC項目中設計并實現(xiàn)了一種新的對象模型,利用現(xiàn)代C編譯器的特性同時結合元編程技巧,在模擬了面向?qū)ο蟮幕咎匦缘耐瑫r,保證了易用性,簡化了開發(fā)的復雜度。對應于圖1 中的例子,這種新的模型的內(nèi)存分布如圖3所示。

        和圖2中C++對象模型一樣的是,將虛表結構和實例結構分離,這樣可以有效的區(qū)分成員和方法,有助于內(nèi)存的節(jié)約。和C++模型的主要不同是將cnt成員放在虛表結構中并在虛表結構中保留了指向方法的指針。同時,在虛表結構中增加了一個實例計數(shù)用的成員。而對于類的方法,因為C語言無法直接去調(diào)用,故在虛表結構中保留了指向其真實函數(shù)地址的函數(shù)指針。

        圖3 OOC-GCC的內(nèi)存模型

        因為不能借助于編譯器,OOC-GCC項目并沒有實現(xiàn)完整的類型系統(tǒng),故省略了C++模型中和類型信息相關的結構,但并不影響對面向?qū)ο笾蟹庋b,繼承,多態(tài)等特性的模擬。如果需要對類型系統(tǒng)的模擬,也可配合GObject中的類型系統(tǒng)使用。

        1.3 支持單根繼承的對象模型

        現(xiàn)假設一個類B繼承了圖1中所表述的類A,那么按照本文中提出的內(nèi)存模型,其具體內(nèi)存分配如圖4所示。

        圖4 OOC-GCC單根繼承對象模型

        2 對象模型的使用

        圖4中看似復雜的內(nèi)存布局,可配合表1中所定義的一些宏一起使用,無需經(jīng)過任何第三方工具即可實現(xiàn)類的設計與使用。

        表1 OOC-GCC宏的定義

        B的實例部分繼承了A的實例部分的內(nèi)容,而B的虛表結構繼承了A的虛表結構的內(nèi)容,但虛表結構頭部的析構指針和實例計數(shù)器部分保持不變。在B的實例中保留有兩個虛表指針,分別指向A的虛表結構以及B的虛表結構。這意味著,即使在沒有分配A的實例的前提下,直接聲明一個B的實例,會同時為之分配A和B的兩個虛表結構,而B的虛表結構因為繼承的原因,也包含了A的虛表結構的內(nèi)容。

        在設計一個類時,CLASS宏和STATIC 宏分別用來定義一個類的實例結構和虛表結構,而與之相應的CLASS_EX 宏以及STATIC_EX 宏則為實例結構和虛表結構的定義增加了對單根繼承特性的支持。ASM和ASM_EX 則是用來將類的定義與實現(xiàn)的類的構造函數(shù)與析構函數(shù)進行綁定。

        在對一個類進行操作時,表1中定義的NEW 宏和DELETE宏和C++中的new 與delete關鍵字十分類似,它們都會在堆內(nèi)存上開辟或釋放一塊區(qū)域并進行對象的構造與析構。NEW0 宏和DELETE0 宏則對應NEW 宏和DELETE宏不接收任何參數(shù)的情形。ST 宏則用來通過實例結構獲取指向虛表結構的指針。*Fn則是對一定形式的函數(shù)指針的類型重定義,如iFn表示返回值為int型的函數(shù)指針,而vFn表示無返回值(返回值為void型)的函數(shù)指針。

        使用表1中的宏來描述圖4中定義的類A和類B的代碼如圖5中所示。

        3 對象模型的設計

        3.1 功能模塊的設計

        OOC-GCC中的模塊如圖6所示。

        OOC-GCC項目由多個模塊構成,這些模塊被定義在與模塊名相對應的.h或.c文件中。其中,最為核心的部分定義在OOCore模塊中。OOBase模塊則對OOCore模塊進行了擴展,使之支持虛表結構以及單根繼承等特性。對于使用者而言,只需關注兩個模塊,一個是OOStd模塊,該模塊用于對底層較復雜的內(nèi)容進行重定義,簡化實際使用時的復雜度;另一個是OOCfg模塊,該模塊用于對整體進行配置。通過OOCfg模塊中的宏開關,可以選擇性的使用調(diào)試用的OODbg模塊,也可以開啟對匿名結構體等特性的支持。

        3.2 實例結構和虛表結構的設計

        為了使表1中和類的設計相關的宏能和圖3中以及圖4中所表述的對象模型相適應,當使用CLASS,STATIC,CLASS_EX,STATIC_EX 宏定義一個類的時候,除了類本身的成員外,還會隱式的引入一些和構造與析構相關的成員。

        每當使用CLASS宏時,都會在一個結構體的頭部放置一個名為OOC_STRUCT__classRootHead的結構體。相應的每當使用STATIC宏時,頭部的結構體名為OOC_STRUCT__staticRootHead。具體的定義如圖7所示。

        圖7 頭部結構設計

        每一個用CLASS定義的結構體的頭部都有一個指向真實虛表結構的指針。每一個STATIC 宏的頭部都有一個指向真實析構函數(shù)的函數(shù)指針,以及一個用于實例計數(shù)的成員變量。通過DELETE宏進行析構時,即調(diào)用圖7中__ooc_classDelete指針指向的函數(shù)。而用于計數(shù)的變量保證了使用者無需關注虛表結構的構造與析構,當一個類的第一實例構造之前,該類的虛表結構已經(jīng)自動構造完成了;而當一個類的最后一個實例銷毀后,該類的虛表結構的析構函數(shù)也會被自動調(diào)用。

        從圖5可以看出,STATIC宏應在CLASS宏后的大括號內(nèi)使用。其不僅引入了虛表結構的頭部,還引入了實例結構的尾部結構。繼承關系每加深一級,會在實例結構的尾部多分配一個雙重泛型指針,用于指向當前類型的虛表結構。而實例結構頭部中虛表指針指向的是最后一級類型的虛表結構。之所以這里采用雙重泛型指針,是為了保證在構造與析構時可以直接通過實例的構造或析構函數(shù)去修改位于虛表結構中的用于實例計數(shù)的成員,同時這樣的設計可以保證宏的靈活性,不會引入額外的全局變量。

        和CLASS 宏以及STATIC 宏不同,支持繼承的宏CLASS_EX 以及STATIC_EX 并不會再次引入實例結構與虛表結構的頭部。

        3.3 構造與析構的設計

        假定要頂一個名為A的類,在使用CLASS和STATIC來定義的時候,在底層定義了名為A和StA的結構體,以及用于分配內(nèi)存的newA 函數(shù)以及newStA 函數(shù),用于釋放內(nèi)存的delA 函數(shù)以及delStA 函數(shù),用于構造的iniA 函數(shù)以及iniStA 函數(shù),用于析構的finA 函數(shù)以及finStA 函數(shù)。在生成與銷毀一個實例時,和虛表結構相關的newStA 函數(shù),delStA 函數(shù),iniStA 函數(shù)以及finStA 函數(shù)會被自動的調(diào)用。而ASM 宏則用來將用戶自己定義的A_reload 函數(shù),A_unload 函數(shù),A_reloadSt函數(shù)以及A_unloadSt函數(shù)與上述的幾個函數(shù)進行綁定。

        以圖5中實例B的構造與析構為例,先使用NEW0宏在堆內(nèi)存聲明一個類B的實例,最后又用DELETE0宏將其銷毀并釋放,期間并沒有其它實例的分配與銷毀。在B的實例聲明和銷毀時,其會按圖8中所示的順序調(diào)用一些構造和析構相關的函數(shù)。

        構造時,第1,2步完成B的虛表結構的構造,第3步完成A的虛表結構的構造,第4,5步完成B的實例結構的構造。而析構時,第1,2步完成B的實例結構的析構,第3步完成A的虛表結構的析構,第4,5步完成B的虛表結構的析構。

        圖8 構造與析構的順序

        可以看出,構造和析構的順序是完全對稱的,并且子類的構造和析構會自動調(diào)用父類的構造和析構,同時,虛表結構的分配與銷毀也是自動的。而這些都是由ASM 宏和ASM_EX 宏保證的。

        當定義的類或聲明的實例更加復雜時,為了減少記憶的負擔,其也應具備對稱性。ASM 宏和ASM_EX 宏保證了其構造與析構過程遵循如下算法。

        構造時,其遵循圖9 中的算法。而析構時,其遵循圖10中的算法。

        3.4 調(diào)試層的設計

        為了方便調(diào)試,OOC-GCC項目中增加了方便調(diào)試程序調(diào)試層,可配合GCC(GNU compiler collection)一起使用。在將調(diào)試層一同編譯時,其會替換NEW 宏中封裝的malloc函數(shù)以及DELETE宏中封裝的free函數(shù),進而可以對內(nèi)存的分配和釋放以記錄并輸出。如果輸出至文件,還配合Graphviz等工具方便的生成函數(shù)調(diào)用圖表。除此之外,OOC-GCC的調(diào)試層還對C++的異常捕獲機制進行了簡單的模擬并提供了運行時間監(jiān)測等實用的功能。

        OOC-GCC中關于類的設計和實現(xiàn)的宏在設計上嚴格的對稱,并沒有引入任何一個全局變量,符合C 語言模塊化的設計原則。也因此,其對調(diào)試層沒有任何依賴。如果某些編譯器不支持調(diào)試層提供的一些功能或是需要發(fā)布程序時,只需移除OODbg模塊,使其不參與編譯即可。

        4 與C++的對比

        為了方便和C++進行比較,須設計一個場景。

        假定現(xiàn)有一個抽象的名為Animal的父類,其包含一個名為name的成員和一個名為talk的方法。另有兩個名為Cat和Dog的子類繼承了Animal這一父類,并各自重寫了父類中定義的talk方法(或重寫了父類中已經(jīng)實現(xiàn)的talk方法)。

        在實際測試的例子中,通過子類來分配內(nèi)存,使用父類的形式來調(diào)用接口來調(diào)用以體現(xiàn)面向?qū)ο笏枷胫械亩鄳B(tài)的特性。一開始,直接在堆內(nèi)存上分配4000個子類的實例(Cat類和Dog類隨機),然后分別調(diào)用其talk方法,最后再依次將其析構。

        實際測試時的C代碼以及C++代碼分別如圖11和圖12所示。

        通過對圖11和圖12的對比可知,實際的代碼長度十分相近。僅僅是需要額外的聲明一個名為StAnimal的實例,并通過ST 宏獲取相應的虛表結構。

        在ubuntu和windows xp系統(tǒng)上測試的關于生成程序體積的數(shù)據(jù)如表2所示(其中數(shù)據(jù)的單位為字節(jié))。

        表2 生成體積對比

        可以看出,從生成代碼體積方面來說,其和使用C++生成的代碼會有些差異,但這些差異并不顯著,并且在開啟優(yōu)化選項后,生成的體積有可能比原生的C++占用更小的空間。

        5 實際的應用

        表1中聲明的宏被設計成跨平臺的,不但支持開源的GCC編譯器,也兼容微軟的MSVC編譯器。對于容量受限或是開發(fā)工具受限的嵌入式平臺,即使無法很好的支持C++等面向?qū)ο蟮木幊陶Z言,也可使用該模型可以大幅提升程序的可讀性和可維護性。實際測試中,AVR,STM32,MSP430 等芯片所使用的編譯器都可以很好的支持。

        另外,利用OOC-GCC 項目中設計的對象模型,還可較為方便的將現(xiàn)有的使用面向?qū)ο笳Z言(如C++,Java,Python等)編寫的代碼移植至純C 語言的平臺,文獻[9]中給出了一個用Java語言實現(xiàn)的簡易解釋器的例子,并且該解釋器的實現(xiàn)符合設計模式中解釋器模式[10]的規(guī)范。

        假定要實現(xiàn)一個具備如下功能的解釋器:可以根據(jù)指定的格式向某終端輸出指定格式的字符串,并支持循環(huán)結構。

        圖13 解釋器的示例與運行結果

        圖13中左側為該解釋器的示例代碼,右側為對應的正確輸出。該例子中共有7個關鍵字。其中PROGRAM 表示程序的開始,與之對應的END 既可用于程序的終結,也可用于循環(huán)結構的終結,而循環(huán)結構用REPEAT 關鍵字來描述,其后緊跟一個數(shù)字,用來指示具體循環(huán)的次數(shù)。PRINT 用于輸出指定的字符串,但由于涉及字符的轉(zhuǎn)義,這里使用SPACE關鍵字來輸出空格,并使用BREAK 關鍵字來輸出換行,而LINEBREAK 關鍵字則在輸出一行直線的同時額外的輸出一個換行。

        將上述描述,可得出該解釋器定義的BNF范式,具體如圖14所示。

        圖14 解釋器的BNF

        在以解釋器模式進行設計時,BNF范式中的每一個節(jié)點都對應一個類,而每個類都應實現(xiàn)一個用于解析代碼并生成需要的AST 樹的接口以及一個對已生成的AST 樹進行遍歷并執(zhí)行接口。如圖14 所示,該范式由program,command list等5個關鍵節(jié)點構成,按照解釋器模式的規(guī)定,需為這5個節(jié)點分別設計具備用來解析字符串和用來執(zhí)行抽象語法樹中定義規(guī)則的方法的類。

        圖15 Repeat節(jié)點C實現(xiàn)

        圖15中展示了使用OOC-GCC配合C 語言以實現(xiàn)用于循環(huán)控制的Repeat節(jié)點的方式,可以看到,配合OOCGCC,C語言在形式上已經(jīng)有明顯的面向?qū)ο蟮纳?。因為該例子較為復雜,完整的實現(xiàn)可從文獻該例子較為復雜,完整的例子可參見文獻[5]中獲得。另外,在文獻[9]中給出了該解釋器分別以JAVA 語言以及Python語言實現(xiàn)的方法。通過對比可以看出,使用Java語言或Python等原生支持面向?qū)ο笏枷氲木幊陶Z言所編寫的代碼在邏輯上可以和使用C語言編寫的具備OO 風格的代碼一一對應,但因為缺乏諸如GC(garbage collector)等特性,在代碼量上,使用C語言編寫的程序仍比使用Java等語言編寫的程序要長一些。

        6 結束語

        利用現(xiàn)代C編譯器的特性以及元編程技巧,配合適用于C語言的對象模型,可以很好的利用面向?qū)ο蟮乃枷耄嵘鼵程序的可重用性。OOC-GCC中的設計,通過宏的方式簡化因引入面向?qū)ο笏枷攵a(chǎn)生的附加代碼,無需借助任何第三方代碼生成工具,很好的將OOP 與C 語言像結合。同時,其靈活的設計,維持了和C++相似的編碼風格,符合C語言模塊化[11]的編碼規(guī)范,不依賴于其它第三方庫,在實際中可以很好的解決大規(guī)模C 代碼難以復用,難以管理的問題。

        相較于著名的GObject庫,這是一種輕量級的實現(xiàn),并沒有提供復雜的對象系統(tǒng),但更加靈活易用,且方便移植。如果需要對象系統(tǒng)的支持,也可配合GObject,Lua,Python[12]以及Ruby中的對象系統(tǒng)一起使用。

        為了方便測試以及推廣文中涉及的代碼。OOC-GCC項目遵循LGPL 3.0開源協(xié)議托管于Google Code,文獻[5]中給出了具體的鏈接,可供讀者測試,驗證和使用。

        [1]Bjarne Stroustrup.Evolving a language in and for the real world:C++1991-2006[C]//HOPL III,Proceedings of the Third ACM SIGPLAN Conference on History of Programming Languages,2007:3-5.

        [2]Bjarne Stroustrup.The Design and evolution of C++[M].QIU Zongyan,transl.China Machine Press,2002:7-37(in Chinese).[Bjarne Stroustrup.C++語言的設計和演化[M].裘宗燕,譯.機械工業(yè)出版社,2002:3-37.]

        [3]ANSI C89Standard,ANSI X3.159-1989[S].

        [4]ISO C99Standard,ISO/IEC 9899:1990[S].

        [5]MENG Fanchao.OOC-GCC project:An easy to use template to write OO program with pure C programming language[CP/OL].http://code.google.com/p/ooc-gcc/,2012(in Chinese).[孟繁超.OOC-GCC[CP/OL].http://code.google.com/p/oocgcc/,2012.]

        [6]Stanley B Lippman.Inside The C++object model[M].HOU Jie,transl.Publishing House of Electronics Industry,2012:1-13(in Chinese).[Stanley B Lippman.深度探索C++對象模型[M].侯捷,譯.電子工業(yè)出版社,2012:1-13.]

        [7]Andrew Krause.Foundations of GTK+development[M].Apress?,2007:406-456.

        [8]SONG Guowei.GTK +2.0 programming paradigm[M].Tsinghua University Press,2002:174-178(in Chinese).[宋國偉:GTK+2.0 編程范例[M].清華大學出版社,2002:174-178]

        [9]LIN Xinliang.Notes about design interpreter pattern[J/OL].http://caterpillar.onlyfun.net/Gossip/DesignPattern/InterpreterPattern.htm,2010(in Chinese).[林信良.關于解釋器模式的筆記[J/OL].http://caterpillar.onlyfun.net/Gossip/DesignPattern/InterpreterPattern.htm,2010.]

        [10]Erich Gamma,Richard Helm,Ralph Johnson,et al.Design patterns:Elements of reusable object-oriented software[M].Addison-Wesley Professional,1995:274-288

        [11]David R Hanson.C interfaces and implementations:Techniques for creating reusable software[M].GUO Xu,transl.Posts &Telecom Press,2011:1-21(in Chinese).[David R Hanson.C語言接口與實現(xiàn):創(chuàng)建可重用軟件的技術[M].郭旭,譯.人民郵電出版社,2011:1-21]

        [12]CHEN Ru.Inside python source code:dig into the core of the dynamic languages[M].Publishing House of Electronics Industry,2008:15-28(in Chinese).[陳儒.Python 源碼剖析:深度探索動態(tài)語言核心技術[M].電子工業(yè)出版社,2008:15-28.]

        猜你喜歡
        定義結構模型
        一半模型
        《形而上學》△卷的結構和位置
        哲學評論(2021年2期)2021-08-22 01:53:34
        重要模型『一線三等角』
        重尾非線性自回歸模型自加權M-估計的漸近分布
        論結構
        中華詩詞(2019年7期)2019-11-25 01:43:04
        論《日出》的結構
        3D打印中的模型分割與打包
        成功的定義
        山東青年(2016年1期)2016-02-28 14:25:25
        創(chuàng)新治理結構促進中小企業(yè)持續(xù)成長
        修辭學的重大定義
        當代修辭學(2014年3期)2014-01-21 02:30:44
        热门精品一区二区三区| 东北妇女xx做爰视频| 国产精品国产三级国产av′| 国产乱人伦真实精品视频| 国产精品亚洲av无人区一区蜜桃| 久久红精品一区二区三区| 久久婷婷人人澡人人喊人人爽| 乱子真实露脸刺激对白| 亚洲中文字幕无线乱码va | 成人久久久精品乱码一区二区三区| 丰满熟女高潮毛茸茸欧洲视频| √天堂中文官网8在线| 欧美综合区自拍亚洲综合| 亚洲美女主播内射在线| 成年女人a级毛片免费观看| 亚洲综合色成在线播放| 亚洲AV秘 无码一区二区在线 | 国产三级国产精品三级在专区 | 久久久久久岛国免费网站| 国产女人精品一区二区三区| 国产a级三级三级三级| 一本一本久久a久久精品综合麻豆| 成人无码a级毛片免费| 亚洲综合一区二区三区在线观看| 精品国品一二三产品区别在线观看| 97久久精品人人做人人爽| 国产日韩久久久久69影院| 高潮精品熟妇一区二区三区| 国产xxx69麻豆国语对白| 美女黄18以下禁止观看| 视频精品亚洲一区二区| 日本最新一区二区三区视频观看| 亚洲精品午睡沙发系列| 久久亚洲日本免费高清一区| 熟女免费观看一区二区| 蜜桃一区二区三区| 亚洲午夜精品a区| 亚洲精品中文字幕乱码三区99 | 国产精品又爽又粗又猛又黄| 97色偷偷色噜噜狠狠爱网站| 久久ri精品高清一区二区三区 |