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