趙 輝,屈 雷
(西安工程大學(xué) 電子信息學(xué)院,陜西 西安 710048)
C語(yǔ)言是在國(guó)內(nèi)外廣泛使用的一種高級(jí)編程語(yǔ)言[1]。其功能豐富、使用靈活方便、目標(biāo)程序效率高、可移植性好,既具有高級(jí)語(yǔ)言的優(yōu)點(diǎn),又具有低級(jí)語(yǔ)言的諸多特性。因此,C語(yǔ)言特別適合用于編寫(xiě)系統(tǒng)軟件[2],其中著名的Linux/Unix操作系統(tǒng)就是用C語(yǔ)言編寫(xiě)而成的[3]。
一般來(lái)說(shuō),C語(yǔ)言是以面向過(guò)程的方式進(jìn)行編程的,用來(lái)編寫(xiě)功能復(fù)雜的軟件是比較困難的[4]。而Linux/Unix操作系統(tǒng)卻是使用C語(yǔ)言編寫(xiě),并與面向?qū)ο蟪绦蛟O(shè)計(jì)的思想相結(jié)合[5],提升了C語(yǔ)言的簡(jiǎn)潔性、易讀性和重復(fù)使用性,進(jìn)而提高了系統(tǒng)分析及結(jié)構(gòu)設(shè)計(jì)的能力[6]。這一例子說(shuō)明,C語(yǔ)言其實(shí)也可以像C++一樣以面向?qū)ο蟮姆绞竭M(jìn)行編程。
本文將通過(guò)電子書(shū)軟件來(lái)具體分析,如何使用面向?qū)ο缶幊讨械囊恍C(jī)制來(lái)實(shí)現(xiàn)C語(yǔ)言的面向?qū)ο笤O(shè)計(jì)。
當(dāng)人們提到面向?qū)ο蟮木幊陶Z(yǔ)言,首先想到的會(huì)是C++。在1985年以前,C++的名字是“C with Class”,從名字上可以看出C++最突出的特征就是類(lèi)(Class);從另一種角度可以看出C++是C語(yǔ)言的有效擴(kuò)充[7]。所以使用ANSI-C進(jìn)行面向?qū)ο蟮木幊蹋罨A(chǔ)的是類(lèi)機(jī)制,而且還需要其他機(jī)制的支持。
“Class”是很多面向?qū)ο缶幊陶Z(yǔ)言里定義類(lèi)的關(guān)鍵字,它來(lái)源于最早的編程語(yǔ)言——smalltalk。類(lèi)是一群具有共同屬性的對(duì)象,說(shuō)明了這群對(duì)象所具有的特征和行為。在程序中,數(shù)據(jù)表示對(duì)象的特征,函數(shù)表示對(duì)象的行為[4]。
類(lèi)可以理解為用戶定義的一種新的數(shù)據(jù)類(lèi)型,就像是“short”這樣的內(nèi)置類(lèi)型一樣。內(nèi)置類(lèi)型已經(jīng)有了一套完善的操作(如算數(shù)運(yùn)算等),類(lèi)機(jī)制也必須規(guī)定他所定義的類(lèi)也能夠進(jìn)行操作,即對(duì)象的行為。在ANSI-C中并沒(méi)有關(guān)鍵字“class”,但是可以使用結(jié)構(gòu)體(struct)來(lái)定義一種新的數(shù)據(jù)類(lèi)型,從而實(shí)現(xiàn)類(lèi)。在結(jié)構(gòu)體定義里,使用變量來(lái)描述對(duì)象的特征,并使用函數(shù)指針來(lái)描述對(duì)象的行為。
面向?qū)ο蟪绦蛟O(shè)計(jì)的主要優(yōu)點(diǎn)之一就是提供軟件元素的重用。它提供了幾種機(jī)制支持利用已有類(lèi)來(lái)定義新類(lèi),新類(lèi)可以獲得已有類(lèi)的特征和行為,進(jìn)而實(shí)現(xiàn)類(lèi)的重用。本文實(shí)現(xiàn)了一種比較簡(jiǎn)單的重用機(jī)制即組合。
組合(composition)表示的是兩個(gè)對(duì)象之間獲得一種包含關(guān)系,即一個(gè)對(duì)象包含或擁有另一個(gè)對(duì)象[8]。擁有其他對(duì)象的對(duì)象被稱(chēng)為組合體,它所擁有的對(duì)象被稱(chēng)為組件。這種關(guān)系在現(xiàn)實(shí)生活中是很普遍的:計(jì)算機(jī)包含處理器,書(shū)本包含文字等。組合使用ANSI-C實(shí)現(xiàn)是很簡(jiǎn)單的。
封裝(encapsulation)是面向?qū)ο蟮牧硪粋€(gè)重要概念。就是把特征和行為包圍起來(lái),對(duì)數(shù)據(jù)的訪問(wèn)只能通過(guò)特定的接口。事實(shí)上,封裝就是用戶對(duì)信息的隱藏,保證了模塊具有較好的獨(dú)立性,使得程序維護(hù)修改較為容易。對(duì)應(yīng)用程序的修改僅限于類(lèi)的內(nèi)部,因而可以將應(yīng)用程序修改帶來(lái)的影響減少到最低限度[9]。
非 OOP(Object Oriented Programming)語(yǔ)言沒(méi)有完備的機(jī)制來(lái)實(shí)現(xiàn)封裝[6]。使用ANSI-C來(lái)實(shí)現(xiàn)封裝稍微有些復(fù)雜。本文使用單向鏈表實(shí)現(xiàn)了對(duì)類(lèi)中所有實(shí)例化的對(duì)象進(jìn)行封裝。
多態(tài)(polymorphism)源于希臘語(yǔ),意思的“多種形狀”。在OOP語(yǔ)言中多態(tài)是指相關(guān)對(duì)象具有不同的成員函數(shù)(函數(shù)原型相同),并且允許對(duì)象與適當(dāng)?shù)某蓡T函數(shù)運(yùn)行時(shí)進(jìn)行動(dòng)態(tài)綁定[6]。多態(tài)保證了軟件設(shè)計(jì)的重復(fù)使用。一般通過(guò)虛方法實(shí)現(xiàn)多態(tài)[10]。
一般情況下,我們使用ANSI-C編程,函數(shù)的原型是對(duì)應(yīng)唯一的函數(shù)實(shí)現(xiàn)。而多態(tài)要求一個(gè)函數(shù)原型可以對(duì)應(yīng)多個(gè)函數(shù)實(shí)現(xiàn),這樣可以便于管理功能相似的模塊。如果前面提到的類(lèi)機(jī)制、重用機(jī)制和封裝機(jī)制都已經(jīng)使用ANSI-C實(shí)現(xiàn),再要實(shí)現(xiàn)多態(tài)機(jī)制就是非常簡(jiǎn)單的事情,使用函數(shù)指針抽象出統(tǒng)一的函數(shù)接口。
整個(gè)軟件使用了ANSI-C編寫(xiě),采用上文所提到的面向?qū)ο蟮膶?shí)現(xiàn)方法,并進(jìn)行模塊化分層設(shè)計(jì)。
(1)支持多種字體編碼方式。文本文件一般有四種編碼方式:ANSI、Unicode、Unicode big endian、UTF-8。程序需要根據(jù)文本文件的編碼方式,自動(dòng)選擇解碼函數(shù)。
(2)支持多種字體顯示方式。常用的字體顯示方式有GBK點(diǎn)陣和freetype矢量字體。程序需要根據(jù)字體設(shè)置,判斷使用哪種方式顯示文字。
(3)支持多種輸入方式。常見(jiàn)的輸入方式有鍵盤(pán)和觸摸屏。程序要根據(jù)鍵盤(pán)的輸入和觸摸屏的滑動(dòng),實(shí)現(xiàn)翻頁(yè)。
(4)支持多種設(shè)備顯示。程序在PC機(jī)上運(yùn)行是,使用PC機(jī)的顯示器(CRT)。程序在ARM上運(yùn)行時(shí),使用ARM上的LCD顯示器。
根據(jù)電子書(shū)軟件需求,將整個(gè)軟件分3層。軟件的層次關(guān)系及各功能模塊構(gòu)成如圖1所示。面向?qū)ο蟮膶?shí)現(xiàn)方法主要體現(xiàn)為4個(gè)基本的底層功能模塊,每個(gè)模塊分別有幾種不同的實(shí)現(xiàn)方式。并由一個(gè)管理文件提供接口函數(shù)對(duì)不同的實(shí)現(xiàn)方式進(jìn)行統(tǒng)一的操作。中間層為電子書(shū)頁(yè)面管理模塊,負(fù)責(zé)調(diào)用底層實(shí)現(xiàn)的接口函數(shù)實(shí)現(xiàn)了字體顯示和頁(yè)面操作以及相關(guān)的初始化。頂層為電子書(shū)管理模塊,負(fù)責(zé)調(diào)用中間層實(shí)現(xiàn)的相關(guān)數(shù)據(jù)管理成個(gè)程序。
(1)使用arm-linux-gcc工具鏈在Ubunut上編譯,在飛凌的ok6410開(kāi)發(fā)板上運(yùn)行,結(jié)果如圖2所示。
(2)首先在Ubunut上移植svgalib庫(kù),其次使用gcc在Ubunut上編譯,最后在Ubunut上的tty控制臺(tái)運(yùn)行程序。結(jié)果如圖3所示。
電子書(shū)程序的代碼量比較大,無(wú)法全部分析。本文將針對(duì)設(shè)備顯示模塊進(jìn)行詳細(xì)分析,具體如下。
圖1 在ARM的LCD上顯示的結(jié)果
圖2 在ARM的LCD上顯示的結(jié)果
圖3 在PC機(jī)的CRT上顯示的結(jié)果
根據(jù)實(shí)驗(yàn)需求,本程序可以在PC機(jī)的CRT上顯示,也可以在ARM的LCD上顯示。所以我們需要操作的對(duì)象就是CRT和LCD。我們能夠抽象出他們的共同特征和行為,得到一個(gè)具體類(lèi),使用結(jié)構(gòu)體實(shí)現(xiàn)。具體代碼如下,這部分定義在disp_manager.h頭文件中:
其中T_Disp結(jié)構(gòu)體是顯示器固有屬性的抽象,也是T_DispOpr類(lèi)的一部分,這樣就可以簡(jiǎn)單的實(shí)現(xiàn)ANSI-C中的類(lèi)和組合機(jī)制。
根據(jù)上文產(chǎn)生的具體類(lèi),實(shí)例化為CRT和LCD對(duì)象,分別實(shí)現(xiàn)在crt.c和lcd.c文件中。一個(gè)C文件實(shí)現(xiàn)具體類(lèi)的一個(gè)實(shí)例化,這樣的模塊化設(shè)計(jì),使得程序進(jìn)行添加和刪除模塊簡(jiǎn)單方便,更容易維護(hù)。由于對(duì)具體類(lèi)的實(shí)例化是非常相似的,本文只對(duì)LCD對(duì)象的實(shí)例化進(jìn)行具體分析,代碼如下:
上面的代碼給出了3個(gè)函數(shù)聲明,具體的實(shí)現(xiàn)過(guò)程略。代碼中使用了“static”關(guān)鍵字,說(shuō)明定義的是靜態(tài)函數(shù)和靜態(tài)變量。這些函數(shù)和變量只能在本文件中被調(diào)用,這也是實(shí)現(xiàn)封裝的基礎(chǔ)。那么上層的函數(shù)怎么調(diào)用這些靜態(tài)函數(shù)和靜態(tài)變量?
在lcd.c文件中需要有一個(gè)入口函數(shù),以便實(shí)現(xiàn)其他文件對(duì)本文件中靜態(tài)函數(shù)和靜態(tài)變量的調(diào)用。代碼如下:
其中RegisterDispOpr()函數(shù)將g_tLCDOpr結(jié)構(gòu)體的地址注冊(cè)到單向鏈表中。上層函數(shù)就是通過(guò)鏈表找到g_tLCDOpr結(jié)構(gòu)體的入口地址,調(diào)用相關(guān)的函數(shù)及變量。實(shí)現(xiàn)了將具體類(lèi)例化的對(duì)象封裝到鏈表中。這個(gè)函數(shù)是在disp_manager.c文件中實(shí)現(xiàn),而在這個(gè)文件中還需要實(shí)現(xiàn)一些操作鏈表的通用函數(shù),方便上層函數(shù)調(diào)用。
在lcd.c文件中
/*LCD設(shè)備初始化函數(shù)*/
.DeviceInit =LCDDeviceInit,
在crt.c文件中
/*CRT設(shè)備初始化函數(shù)*/
.DeviceInit =CRTDeviceInit,
程序在調(diào)用這個(gè)兩個(gè)函數(shù)時(shí),使用的是同一個(gè)接口 g_ptDispOpr->DeviceInit(),這就是多態(tài)的實(shí)現(xiàn)。程序先在鏈表中根據(jù)g_ptDispOpr->name查找,返回相應(yīng)name的結(jié)構(gòu)體的入口地址,進(jìn)而就確定了g_ptDispOpr->DeviceInit()接口對(duì)應(yīng)的是哪個(gè)具體的實(shí)現(xiàn)過(guò)程。
如今嵌入式軟件應(yīng)用愈來(lái)愈廣,軟件的質(zhì)量決定了數(shù)碼產(chǎn)品的穩(wěn)定性和可靠性。本文的實(shí)現(xiàn)的這些機(jī)制對(duì)于嵌入式軟件編程是大有裨益。但是,對(duì)于大型的軟件系統(tǒng)來(lái)說(shuō),本文實(shí)現(xiàn)的這些機(jī)制是遠(yuǎn)遠(yuǎn)不夠的??赡苓€需要超類(lèi)、繼承、內(nèi)存泄漏檢測(cè)等機(jī)制的支持。
[1]黃俊爽,郭凌云,李燕杰,等.淺析C語(yǔ)言中常見(jiàn)錯(cuò)誤[J].電腦知識(shí)與技術(shù),2010(12):60.
[2]譚浩強(qiáng).C語(yǔ)言程序設(shè)計(jì)[M].3版.北京:清華大學(xué)出版社,2005.
[3]丁慧.用C語(yǔ)言實(shí)現(xiàn)面向?qū)ο笱芯縖J].淮海工學(xué)院學(xué)報(bào):社會(huì)科學(xué)版,2010,8(12):61-63.
[4]曹燁.淺談C語(yǔ)言與匯編語(yǔ)言混合編程的實(shí)現(xiàn)[J].科技信息:科學(xué)教研,2008(17):1001-9960.
[5]高煥堂.UML+OOPC嵌入式C語(yǔ)言開(kāi)發(fā)精講[M].北京:電子工業(yè)出版社,2008.
[6]陳飛,陳啟安.面向?qū)ο蟮那度胧较到y(tǒng)開(kāi)發(fā)技術(shù)[J].單片機(jī)與嵌入式系統(tǒng)應(yīng)用,2005,5(9):15-18.
[7]LINDEN P V D,徐波.C專(zhuān)家編程[M].北京:人民郵電出版社,2002.
[8]LASZLO M J,楊秀梅,何玉潔,等.面向?qū)ο蟪绦蛟O(shè)計(jì)——圖形應(yīng)用實(shí)例[M].北京:機(jī)械工業(yè)出版社,2002.
[9]鄧正宏,薛靜,鄭玉山.面向?qū)ο蠹夹g(shù)[M].北京:國(guó)防工業(yè)出版社,2004.
[10]丁智,王睿,高艷萍,等.標(biāo)準(zhǔn)C實(shí)現(xiàn)面向?qū)ο缶幊蘙J].江西科學(xué),2009,27(5):733-736.
咸陽(yáng)師范學(xué)院學(xué)報(bào)2015年6期