陳南京 萬(wàn) 瑾
摘要:C++程序良好的可移植性使得C++語(yǔ)言成為程序設(shè)計(jì)人員的首選工具語(yǔ)言,而保證這一特性必需使用標(biāo)準(zhǔn)化的C++編碼。國(guó)內(nèi)高校尤其是高職院校的教材中,存在著大量非標(biāo)準(zhǔn)化的C++程序,不利于培養(yǎng)具有標(biāo)準(zhǔn)化C++編程風(fēng)格的學(xué)生。本文從C++發(fā)展史、教育工作者和教材規(guī)范化等多個(gè)角度出發(fā),分析了這一問(wèn)題產(chǎn)生的原因,并提出了相應(yīng)的解決辦法。
關(guān)鍵詞:C++標(biāo)準(zhǔn);可移植性;高等教育
中圖分類號(hào):TP311文獻(xiàn)標(biāo)識(shí)碼:A文章編號(hào):1009-3044(2008)18-21ppp-0c
1 引言
1983年第一個(gè)C++程序投入使用,1994年8月,ANSI/ISO委員會(huì)草案登記,這便是業(yè)內(nèi)所稱的早期的C++標(biāo)準(zhǔn),1998年11月,ISO/IEC:98-14882標(biāo)準(zhǔn)(以下簡(jiǎn)稱98標(biāo)準(zhǔn))被批準(zhǔn),標(biāo)志著C++代碼的標(biāo)準(zhǔn)化正式誕生[1]。C++語(yǔ)言誕生以來(lái),延續(xù)了C語(yǔ)言的重要特征,即C++源程序良好的可移植性。正是這一特性,使得C/C++語(yǔ)言長(zhǎng)期以來(lái)一直是程序開發(fā)人員的首選。
C++語(yǔ)言良好的可移植性是它具有較強(qiáng)生命力的關(guān)鍵所在。目前標(biāo)準(zhǔn)委員會(huì)正在修訂C++標(biāo)準(zhǔn),并擬于2009年發(fā)布修訂后的09標(biāo)準(zhǔn)??梢灶A(yù)見,C++語(yǔ)言作為程序開發(fā)的主要工具仍將延續(xù)很長(zhǎng)的一段時(shí)間。然而,國(guó)內(nèi)高等教育尤其是高職教育,在C++語(yǔ)言的教學(xué)中卻長(zhǎng)期使用了非標(biāo)準(zhǔn)化的編碼方式,這對(duì)于學(xué)生畢業(yè)后從事程序設(shè)計(jì),寫出具有良好可移植性的程序是相當(dāng)不利的。
C++程序編碼的標(biāo)準(zhǔn)化在互聯(lián)網(wǎng)的一些論壇里有一些討論,然而關(guān)于現(xiàn)行教材或?qū)V锎嬖诘膯?wèn)題,卻鮮有文章進(jìn)行報(bào)道。本文通過(guò)討論現(xiàn)有高校教材尤其是高職教材中C++代碼編寫方式與現(xiàn)行C++標(biāo)準(zhǔn)的一些距離,試圖引導(dǎo)高校教材尤其是高職教材中C++程序編碼走向標(biāo)準(zhǔn)化。
2 標(biāo)準(zhǔn)化的目的和意義
標(biāo)準(zhǔn)化之爭(zhēng)是信息時(shí)代商業(yè)競(jìng)爭(zhēng)乃至國(guó)家之間競(jìng)爭(zhēng)的必爭(zhēng)之地。歐美的企業(yè)一直依賴都很熱衷于標(biāo)準(zhǔn)化之爭(zhēng),UNIX從誕生到現(xiàn)在的各自為政就是一個(gè)很好的例子。而IT領(lǐng)域信息技術(shù)的高度集中和相對(duì)壟斷也使得國(guó)際標(biāo)準(zhǔn)化組織制定的很多標(biāo)準(zhǔn)并沒有被企業(yè)所采用,相反地,出現(xiàn)了很多像“Microsoft Windows”、“Internet Explorer”這種“事實(shí)上的工業(yè)標(biāo)準(zhǔn)”。C++語(yǔ)言從誕生到98標(biāo)準(zhǔn)誕生,花了整整15年的時(shí)間,對(duì)于發(fā)展迅猛的信息技術(shù),這是一個(gè)相當(dāng)漫長(zhǎng)的過(guò)程。在此期間,國(guó)際上一些跨國(guó)公司如Microsoft、IBM、Borland(如今的Inprise)相繼開發(fā)了自己的C++編譯器,這些公司的編譯器除了包含標(biāo)準(zhǔn)的C++編譯器的內(nèi)容之外,還加入了自己的一些特性,甚至修改了部分標(biāo)準(zhǔn)。一旦程序設(shè)計(jì)人員使用了這些非標(biāo)準(zhǔn)的特性,代碼的可移植性將會(huì)成為一個(gè)大問(wèn)題。因此,如何教導(dǎo)學(xué)生編寫標(biāo)準(zhǔn)化的C++源程序,成為C++語(yǔ)言教學(xué)中一個(gè)非常重要的問(wèn)題。
3 C++語(yǔ)言教學(xué)中存在的非標(biāo)準(zhǔn)化編碼的主要問(wèn)題
Microsoft公司曾經(jīng)因?yàn)槠湓谲浖袠I(yè)得天獨(dú)厚的地位,而在MS Visual C++編譯器中采使用了很多非標(biāo)準(zhǔn)化的內(nèi)容。然而,在MS Visual Studio 2005發(fā)布之后,Microsoft公司相關(guān)人員特別指出該產(chǎn)品的一個(gè)重要變化就是完全符合98標(biāo)準(zhǔn)[2]。對(duì)于程序員來(lái)說(shuō),如果他原先在MS Visual C++中使用了非標(biāo)準(zhǔn)化的代碼,在移植到MS Visual Studio2005這個(gè)平臺(tái)上時(shí)將會(huì)花費(fèi)相當(dāng)大的精力去修改代碼。即便是微軟這樣一個(gè)跨國(guó)企業(yè),都不得不向國(guó)際標(biāo)準(zhǔn)靠攏,可想而知,標(biāo)準(zhǔn)化對(duì)于企業(yè)來(lái)講是多么重要了。對(duì)于程序員,如何編寫標(biāo)準(zhǔn)化的C++代碼,保持C++代碼的良好可移植性則是重中之重。然而,在我國(guó)的高校尤其是高職教材中卻存在著甚至是大量存在著非標(biāo)準(zhǔn)化的C++程序,究其原因,筆者認(rèn)為主要有如下幾個(gè)方面:
3.1 C語(yǔ)言的影響
這也是最重要的一點(diǎn)。我國(guó)高校早期從事C++語(yǔ)言的教學(xué)和傳播者主要是從C語(yǔ)言的使用者轉(zhuǎn)移過(guò)來(lái),C++語(yǔ)言的向下兼容性(即兼容C語(yǔ)言書寫的源程序)使得這批教師能夠較快的勝任C++語(yǔ)言的教學(xué)工作。不可否認(rèn),他們對(duì)中國(guó)高等教育的C++語(yǔ)言的教學(xué)和普及做出了不可磨滅的貢獻(xiàn)。然而,C++語(yǔ)言所倡導(dǎo)的面向?qū)ο蟪绦蛟O(shè)計(jì)方法和C語(yǔ)言的面向過(guò)程程序設(shè)計(jì)方法還是存在著很大區(qū)別的,尤其是面向?qū)ο笠髮?duì)數(shù)據(jù)進(jìn)行封裝保護(hù)的機(jī)制在C語(yǔ)言中是不存在的。而我們的第一批C++語(yǔ)言的傳播者以及教材的編著者,卻把C語(yǔ)言的風(fēng)格和編程習(xí)慣帶到了C++語(yǔ)言的教學(xué)中來(lái),并且一直延續(xù)至今。例如:在C語(yǔ)言中主函數(shù)main是可以沒有返回值的,即返回值類型可以是void,而在C++標(biāo)準(zhǔn)中,明確要求主函數(shù)main必須返回int類型。再例如,C語(yǔ)言中人們習(xí)慣使用字符數(shù)組或字符指針來(lái)保存字符串如char name[30], char *str等,而在C++中,提倡使用string對(duì)象來(lái)替代字符數(shù)組的變量。在我所使用的“十一五”國(guó)家級(jí)規(guī)范教材[3]中,從頭到尾使用的都是字符數(shù)組和字符指針,而沒有一處使用string對(duì)象,這明顯違背了C++面向?qū)ο蟪绦蛟O(shè)計(jì)方法的精神。
有人問(wèn)及C++語(yǔ)言的創(chuàng)始人也是C++標(biāo)準(zhǔn)的制定者之一Bjarne Stroustrup博士,有沒有想過(guò)刪除一些C++語(yǔ)言的特性。Bjarne Stroustrup博士說(shuō):從語(yǔ)言設(shè)計(jì)的角度講,我最不喜歡的部分是與C兼容的那個(gè)子集[4]。然而,出于對(duì)現(xiàn)實(shí)世界里工作的程序員的考慮,保留與C兼容的子集是有必要的,但這并不意味著我們要寫出C風(fēng)格的C++程序。
3.2 大量非標(biāo)準(zhǔn)化編譯器的影響
C語(yǔ)言和C++語(yǔ)言都是在UNIX平臺(tái)下誕生的,在UNIX平臺(tái)下使用的都是標(biāo)準(zhǔn)的編譯器G++。而國(guó)內(nèi)由于種種原因,UNIX平臺(tái)一直未能進(jìn)入主流的應(yīng)用,大多數(shù)的企事業(yè)單位包括高校使用的都是MS Windows平臺(tái),高校教育又過(guò)分的偏愛了MS Visual C++這一典型的非標(biāo)準(zhǔn)C++編譯器,即便是計(jì)算機(jī)等級(jí)考試這一全國(guó)性的考試,在C/C++的編程環(huán)境上也是選擇了MS Visual C++。MS Visual C++編譯器包含了很多與C++標(biāo)準(zhǔn)有出入的功能。這在某種程度上助長(zhǎng)了C++的教學(xué)者編寫出大量的非標(biāo)準(zhǔn)化代碼。例如大家所熟悉的eof()函數(shù),該函數(shù)根據(jù)當(dāng)前指針是否指向文件結(jié)束部分而相應(yīng)的返回true和false兩個(gè)值,即當(dāng)我們從一個(gè)文本文件讀取數(shù)據(jù)時(shí),如果指針指向文件的尾部則返回true,如果指針還未指向文件的尾部則返回false。MS Visual C++的編譯器和基于標(biāo)準(zhǔn)C++的編譯器如Dev-C++編譯器對(duì)這個(gè)函數(shù)的處理卻有很大的不同[5]。標(biāo)準(zhǔn)編譯器在第一次讀取文件的最后一個(gè)數(shù)據(jù)后仍然返回false,只有在試圖繼續(xù)讀取數(shù)據(jù)時(shí)發(fā)現(xiàn)已經(jīng)到了文件的結(jié)尾才返回true,而MS Visual C++編譯器則在我們讀取到文件的最后一個(gè)數(shù)據(jù)之后就返回true了。這樣,針對(duì)不同的編譯器,下面的這一段代碼就有了不同的結(jié)果:
void totalFile(char *fName, float &total)
{
fstream rawData;
float itemPrice;
total = (float) 0.0;
rawData.open( fName, ios::in);
while(!rawData.eof())
{
rawData >> itemPrice;
total += itemPrice;
}
rawData.close();
}
假設(shè)我們的文本文件包含兩個(gè)數(shù)據(jù),如下:
6.00
1.25
如果我們使用MS Visual C++編譯器,則最后得到的total值是7.25,而當(dāng)我們用標(biāo)準(zhǔn)C++編譯器如Dev-C++編譯器,得到的結(jié)果則是8.5。對(duì)于MS Visual C++編譯器而言,在讀取1.25之后就認(rèn)為文件已經(jīng)結(jié)束,并且令eof()函數(shù)返回true值,while循環(huán)結(jié)束;而對(duì)于Dev-C++編譯器,讀取1.25后并沒有認(rèn)為文件已經(jīng)到達(dá)尾部,因此,eof()返回的是false,循環(huán)繼續(xù)執(zhí)行,在試圖繼續(xù)讀取數(shù)據(jù)時(shí)才知道文件已經(jīng)結(jié)束,但此時(shí)的循環(huán)體多執(zhí)行了一次,所以如果不作判斷而直接使用上面的代碼,則最后一個(gè)數(shù)據(jù)將會(huì)兩次被加到total上。因此,要得到準(zhǔn)確的結(jié)果7.25,標(biāo)準(zhǔn)C++的代碼應(yīng)該是這樣的:
void totalFile(char *fName, float &total)
{
fstream rawData;
float itemPrice;
total = (float) 0.0;
rawData.open( fName, ios::in);
while(!rawData.eof())
{
rawData >> itemPrice;
if(!rawData.eof())/*這邊增加一個(gè)判斷,
以避免讀取的最后一個(gè)數(shù)據(jù)被運(yùn)算兩次 */
total += itemPrice;
}
rawData.close();
}
從上面的例子我們可以看出,基于非標(biāo)準(zhǔn)C++的編譯器和標(biāo)準(zhǔn)C++的編譯器在一些地方會(huì)有很大的出入,這種情況下,如果毫不知情的將非標(biāo)準(zhǔn)的C++代碼移植到標(biāo)準(zhǔn)C++的編譯器中進(jìn)行編譯,無(wú)疑將會(huì)得到意想不到的結(jié)果??梢?,只有編寫出標(biāo)準(zhǔn)的C++代碼,才能滿足程序的可移植性這一重要特點(diǎn)。
3.3 國(guó)內(nèi)部分教育者對(duì)國(guó)際標(biāo)準(zhǔn)的漠視
國(guó)內(nèi)程序設(shè)計(jì)語(yǔ)言如C++語(yǔ)言的傳播者(以高校教師為主)甚少關(guān)注國(guó)際標(biāo)準(zhǔn),很多老師甚至于不知道自己寫出來(lái)的程序是否符合國(guó)際標(biāo)準(zhǔn),通常情況下只是簡(jiǎn)單的將寫出來(lái)的程序在某一特定編譯器下編譯測(cè)試通過(guò)就草草了事,導(dǎo)致C++語(yǔ)言教學(xué)的教材和各類專著充斥著大量的非標(biāo)準(zhǔn)代碼。國(guó)際標(biāo)準(zhǔn)委員會(huì)為了讓C++語(yǔ)言更好的實(shí)現(xiàn)面向?qū)ο蟪绦蛟O(shè)計(jì)的封裝,在頒布的98標(biāo)準(zhǔn)中對(duì)原先提交的標(biāo)準(zhǔn)進(jìn)行了一些修訂,同時(shí)為了使得原有的程序不至于全部都要進(jìn)行修改,保留了對(duì)原有標(biāo)準(zhǔn)的兼容性。而國(guó)內(nèi)的高校教材中卻很少對(duì)這些標(biāo)準(zhǔn)進(jìn)行深入的研究。例如頭文件包含
#include
這樣的寫法,在98標(biāo)準(zhǔn)中已經(jīng)被廢棄了,而改為使用不含.h的標(biāo)準(zhǔn)寫法。
#include
原因之一是隨著時(shí)間的推移,還能夠繼續(xù)支持.h的頭文件包含的編譯器將會(huì)越來(lái)越少,其次,標(biāo)準(zhǔn)寫法在多個(gè)方面顯示出了它的優(yōu)越性,如對(duì)異常的捕獲和處理、與其它C++標(biāo)準(zhǔn)類對(duì)象在接口方面的結(jié)合更緊密以及對(duì)本地化更好地支持,更為重要的一點(diǎn)是,iostream所定義的組件被聲明為命名空間std的成員,而iostream.h定義的組件則被聲明為全局的,不利于實(shí)現(xiàn)面向?qū)ο蟮姆庋b性。然而,國(guó)內(nèi)教材中卻大量使用了前一種被廢棄的寫法。
3.4 國(guó)內(nèi)教材出版業(yè)的規(guī)范化有待完善。
由于眾所周知的原因,國(guó)內(nèi)高校教師出版教材很多時(shí)候是迫于壓力不得不做的事情,而出版業(yè)的過(guò)分商業(yè)化在一定程度上助長(zhǎng)了這種風(fēng)氣,導(dǎo)致國(guó)內(nèi)出版的教材良莠不齊。盡管近些年在引進(jìn)國(guó)外的優(yōu)秀圖書方面出版界作了很大的努力,但是對(duì)于教材審查和出版的相對(duì)放松在廣大學(xué)生中形成的不好的編程習(xí)慣是很難一下子扭轉(zhuǎn)過(guò)來(lái)的,特別是高職院校的教材主要是以高職院校的教師自己編寫的為主。Bjarne Stroustrup博士在談到如何選擇學(xué)習(xí)C++語(yǔ)言的書籍時(shí)說(shuō)到:務(wù)必注意該書是不是從一開始就講授標(biāo)準(zhǔn)C++,并且矢志不渝地使用標(biāo)準(zhǔn)庫(kù)機(jī)制[4]。例如,從輸入中讀取一個(gè)字符串應(yīng)該是這樣的:
string s; /*標(biāo)準(zhǔn)C++程序的風(fēng)格*/
cin>>s;
而不是這樣的:
char s[MAX]; /*標(biāo)準(zhǔn)C程序的風(fēng)格*/
scanf("%s",s);
可惜,在國(guó)內(nèi)很多C++語(yǔ)言教材中都采用了后者,完全符合C++標(biāo)準(zhǔn)的高校教材是少之又少。
4 問(wèn)題的解決
造成C++語(yǔ)言教材和專著中大量存在著非標(biāo)準(zhǔn)化代碼的原因是多方面的,因此,要解決這個(gè)問(wèn)題,我認(rèn)為,應(yīng)該從以下幾個(gè)方面入手:
1) 選擇標(biāo)準(zhǔn)化的C++編譯器。標(biāo)準(zhǔn)化的C++編譯器在編譯非標(biāo)準(zhǔn)的C++代碼時(shí)會(huì)給出警告信息,編譯人員可以根據(jù)警告信息修改自己的代碼,使之符合標(biāo)準(zhǔn)C++程序的編碼風(fēng)格;
2) 提高教材或?qū)V霭嬲哂绕涫歉咝=處熥陨淼乃刭|(zhì)。標(biāo)準(zhǔn)C++編譯器不是萬(wàn)能的,例如上面所提到的eof()函數(shù)存在的問(wèn)題,是編譯器沒有辦法檢查出來(lái)的。作為知識(shí)的傳播者,高校教師應(yīng)該努力學(xué)習(xí)本行業(yè)的相關(guān)標(biāo)準(zhǔn),寫出符合國(guó)際標(biāo)準(zhǔn)的代碼,使之具有良好的可移植性;
3) 提倡教材編寫與標(biāo)準(zhǔn)化相接軌,規(guī)范教材的編寫和嚴(yán)格教材的出版。出版社應(yīng)該組織權(quán)威的專家對(duì)準(zhǔn)備出版的教材進(jìn)行嚴(yán)格的審查,對(duì)不符合國(guó)際標(biāo)準(zhǔn)的寫法予以糾正。這點(diǎn)在本科和研究生的教材出版中作的相對(duì)較好,而在剛起步而又發(fā)展迅猛的高職教材中問(wèn)題較多。
參考文獻(xiàn):
[1] Juan Soulie. History of C++. [2008-1-18]. http://www.cplusplus.com/info/history.html.
[2] Bradley L. Jones. Breaking Changes in Visual C++ 2005. http://www.developer.com/net/cplus/article.php/3493706.
[3] 吳紹根,陳建潮,張嬋 著. C++面向?qū)ο蟪绦蛟O(shè)計(jì)[M]. 清華大學(xué)出版社,2007.
[4] Bjarne Stroustrup. Bjarne Stroustrup's FAQ. http://www.research.att.com/~bs/bs_faq.html. [2008-2-5].
[5] Laurence Boxer. Porting Code between Language Implementations. http://purple.niagara.edu/boxer/essays/prog/porting.htm.
收稿日期:2008-04-18
作者簡(jiǎn)介:陳南京(1977-),碩士研究生,現(xiàn)就職于廈門華廈職業(yè)學(xué)院工科部,擔(dān)任計(jì)算機(jī)教研室主任。