《軟件工程與項(xiàng)目管理》課件-第7章_第1頁
《軟件工程與項(xiàng)目管理》課件-第7章_第2頁
《軟件工程與項(xiàng)目管理》課件-第7章_第3頁
《軟件工程與項(xiàng)目管理》課件-第7章_第4頁
《軟件工程與項(xiàng)目管理》課件-第7章_第5頁
已閱讀5頁,還剩130頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

第7章軟件編碼7.1軟件編碼的目的7.2程序設(shè)計語言7.3結(jié)構(gòu)化程序設(shè)計7.4編碼風(fēng)格7.5程序編碼優(yōu)化技術(shù)7.6代碼評審和版本控制7.7實(shí)戰(zhàn)訓(xùn)練 7.1軟件編碼的目的

作為軟件工程的一個步驟,軟件編碼是軟件設(shè)計的自然結(jié)果。編碼階段的主要任務(wù)是根據(jù)軟件詳細(xì)設(shè)計階段產(chǎn)生的每個模塊的詳細(xì)設(shè)計說明書,以某種程序設(shè)計語言編寫源程序。

為了提高系統(tǒng)的可維護(hù)性,除要求得到的源程序語法正確外,還要求有較好的可讀性、可靠性和可測試性。同時,編程語言的特性以及編寫程序的風(fēng)格也將深刻地影響軟件的質(zhì)量和可維護(hù)性。

7.2程序設(shè)計語言

7.2.1程序設(shè)計語言的分類

目前,用于軟件開發(fā)的程序設(shè)計語言已經(jīng)有數(shù)百種之多,對這些程序設(shè)計語言的分類有不少爭議,同一種語言可以歸到不同的類中。

從軟件工程的角度看,根據(jù)程序設(shè)計語言發(fā)展的歷程,可以把它們大致分為5類。

(1)機(jī)器語言(第一代語言)。機(jī)器語言是由機(jī)器指令代碼組成的語言。對于不同的機(jī)器,就有相應(yīng)的一套機(jī)器語言。用這種語言編寫的程序,都是二進(jìn)制代碼的形式,且所有的地址都是以絕對地址的形式分配的。存儲空間的安排,寄存器、變址的使用都由程序員自己計劃。因此使用機(jī)器語言編寫的程序很不直觀,在計算機(jī)內(nèi)的運(yùn)行效率很高但出錯率也高。

(2)匯編語言(第二代語言)。匯編語言比機(jī)器語言直觀,它的每一條符號指令與相應(yīng)的機(jī)器指令有對應(yīng)關(guān)系,同時又增加了一些諸如宏、符號地址等功能。存儲空間的安排可由機(jī)器解決。不同指令集的處理器系統(tǒng)有自己相應(yīng)的匯編語言。從軟件工程的角度來看,

匯編語言只在高級語言無法滿足設(shè)計要求時或者不具備支持某種特定功能(例如特殊的輸入/輸出)的技術(shù)性能時才被使用。

(3)高級程序設(shè)計語言(第三代語言)。高級程序設(shè)計語言是算法語言。為了解決編程人員的困難,20世紀(jì)50年代中期出現(xiàn)了第一個算法語言——FORTRAN語言,后來又相繼出現(xiàn)了COBOL、ALGOL60、BASIC、PL/1、PASCAL、MODULA-2、C、Ada等語言。這些算法語言的特點(diǎn)是:用一種接近于自然語言和數(shù)學(xué)的專用語言來表示算法。算法語言不依賴于計算機(jī)硬件,是面向過程的語言。

(4)第四代語言(4GL)。4GL用不同的文法表示程序結(jié)構(gòu)和數(shù)據(jù)結(jié)構(gòu),它是在更高一級抽象的層次上表示這些結(jié)構(gòu)的,它不再需要規(guī)定算法的細(xì)節(jié)。4GL兼有過程性和非過程性兩重特性。程序員規(guī)定條件和相應(yīng)的動作是過程性的部分,指出想要的結(jié)果是非過程性的部分,然后由4GL語言系統(tǒng)運(yùn)用它的專門領(lǐng)域的知識來填充過程細(xì)節(jié)。第四代語言可以分為以下幾種類型:

①查詢語言:用戶可利用查詢語言對預(yù)先定義在數(shù)據(jù)庫中的信息進(jìn)行較復(fù)雜的操作。

②程序生成器:只需很少的語句就能生成完整的第三代語言程序,它不必依賴預(yù)先定義的數(shù)據(jù)庫作為它的著眼點(diǎn)。

③其他4GL:判定支持語言、原型語言、形式化規(guī)格說明語言等。

(5)新型程序設(shè)計語言(第五代語言)。第五代語言是一種新型程序設(shè)計語言。第三代語言的發(fā)展一直受到馮·諾依曼概念的制約,存在許多局限性。進(jìn)入20世紀(jì)60年代后,擺脫馮·諾依曼概念的束縛已成為眾多語言學(xué)家為之奮斗的目標(biāo),為此目標(biāo)而研制的語言被稱為新型程序設(shè)計語言,也稱為知識型程序設(shè)計語言。新型程序設(shè)計語言力求擺脫傳統(tǒng)語言那種狀態(tài)轉(zhuǎn)換語義的模式,以適應(yīng)現(xiàn)代計算機(jī)系統(tǒng)知識化、智能化的發(fā)展趨勢。新型程序設(shè)計語言基本上可以分為函數(shù)型語言、邏輯型語言和面向?qū)ο笮驼Z言。7.2.2程序設(shè)計語言特性的比較

我們從以下三種角度來比較程序設(shè)計語言的特性:

(1)心理學(xué)的觀點(diǎn)。從設(shè)計到編碼的轉(zhuǎn)換基本上是人的活動,因此語言的性能對程序員的心理作用將對轉(zhuǎn)換產(chǎn)生重大影響。程序員總是希望選擇簡單易學(xué)、使用方便的語言,以減少程序出錯率,提高軟件可靠性。從心理學(xué)的觀點(diǎn)看,影響程序員心理的語言特性有如下六種:

①一致性。它表示一種語言所使用符號的兼容程度、允許隨意規(guī)定限制以及允許對語法或語義破例的程度。比如同一個符號若給予多種用途,會引起許多難以察覺的錯誤。②二義性。雖然語言的編譯程序總是以一種機(jī)械的規(guī)則來解釋語句,但讀者則可能用不同的方式來理解語句。例如,對于一個邏輯表達(dá)式A≥"0"andA≤"9",讀者可能有不同的理解。如果一個程序設(shè)計語言缺乏一致性且存在二義性,那么用這種語言編寫出來的程序的可讀性就差,同時用這種語言編程也容易出錯。③簡潔性(緊湊性)。簡潔性表示程序員為了用該語言編寫程序,必須記憶的有關(guān)編碼的信息量,可用語言支持塊結(jié)構(gòu)和結(jié)構(gòu)化程序的能力、可使用的保留字和縮寫字的種類、數(shù)據(jù)類型的種類和缺省說明、算術(shù)運(yùn)算符和邏輯運(yùn)算符的種類、系統(tǒng)內(nèi)標(biāo)準(zhǔn)函數(shù)的數(shù)目等來衡量。遺憾的是,語言的簡潔性與程序的一致性常常是抵觸的。

④局部性。局部性指程序設(shè)計語言的聯(lián)想(綜合)特性。綜合特性使人們能夠?qū)κ挛飶恼w上進(jìn)行記憶和識別。在編碼過程中,由語句組合成模塊,由模塊組裝為程序體系結(jié)構(gòu),并在組裝過程中實(shí)現(xiàn)模塊的高內(nèi)聚和低耦合,可使程序的局部性加強(qiáng)。⑤線性。線性指程序的聯(lián)想(順序)特性。人們總是習(xí)慣于按邏輯線性序列理解程序。如果程序中線性序列和邏輯運(yùn)算較多,會提高可讀性。如果存在大量的分支和循環(huán),就會破壞順序狀態(tài),增加理解上的困難。直接實(shí)現(xiàn)結(jié)構(gòu)化程序可提高程序的線性特性。

⑥傳統(tǒng)。人們學(xué)習(xí)一種新的程序設(shè)計語言的能力受到傳統(tǒng)的影響。比如,具有PASCAL語言基礎(chǔ)的程序人員在學(xué)習(xí)C語言時不會感到困難,因?yàn)镃語言保持了PASCAL語言所確立的傳統(tǒng)語言特性。但是要求同一個人去學(xué)習(xí)APL或者LISP這樣一些語言,傳統(tǒng)就中斷了。

(2)軟件工程觀點(diǎn)。從軟件工程觀點(diǎn)看,程序設(shè)計語言的特性應(yīng)著重考慮軟件開發(fā)項(xiàng)目的需要。為此,對于程序編碼,有如下一些工程上的性能要求:

①詳細(xì)設(shè)計應(yīng)能直接且容易地翻譯成代碼程序。把設(shè)計變?yōu)槌绦虻碾y易程度反映了程序設(shè)計語言與設(shè)計說明相接近的程度。所選擇的程序設(shè)計語言是否具有結(jié)構(gòu)化的構(gòu)造、復(fù)雜的數(shù)據(jù)結(jié)構(gòu)、專門的輸入/輸出能力、位運(yùn)算和串處理的能力,直接影響從詳細(xì)設(shè)計變換到代碼程序的難易程度,以及特定軟件開發(fā)項(xiàng)目的可實(shí)現(xiàn)性。②源程序應(yīng)具有可移植性。源程序的可移植性通常有三種解釋:①對源程序不做修改或少做修改就可以實(shí)現(xiàn)處理機(jī)上的移植或編譯程序上的移植;②即使程序的運(yùn)行環(huán)境改變(例如改用一個新版本的操作系統(tǒng))了,源程序也不用改變;③源程序的許多模塊可以不做修改或少做修改就能集成為功能性的各種軟件包,以適應(yīng)不同的需要。

為改善軟件的可移植性,應(yīng)使語言標(biāo)準(zhǔn)化。在開發(fā)軟件時,應(yīng)嚴(yán)格地遵守ISO或ANSI、GB的標(biāo)準(zhǔn),而不要去理會特定編譯器提供的非標(biāo)準(zhǔn)特性。③編譯程序應(yīng)具有較高的效率。

④盡可能應(yīng)用代碼自動生成工具。有效的軟件開發(fā)工具是縮短編碼時間、改善源代碼質(zhì)量的關(guān)鍵因素。使用帶有各種有效的自動化工具的“軟件開發(fā)環(huán)境”,支持從設(shè)計到源代碼的翻譯等各項(xiàng)工作,可以保證軟件開發(fā)獲得成功。

⑤可維護(hù)性。源程序的可讀性,語言自身的文檔化特性(涉及標(biāo)識符的允許長度、標(biāo)號命名、數(shù)據(jù)類型的豐富程度、控制結(jié)構(gòu)的規(guī)定等)是影響可維護(hù)性的重要因素。

(3)程序設(shè)計語言的技術(shù)性能。在計劃階段,極少考慮程序設(shè)計語言的技術(shù)特性。但在選定資源,要規(guī)劃將要使用的支撐工具時,就要確定一個具體的編譯器或者確定一個程序設(shè)計環(huán)境。如果軟件開發(fā)組的成員對所要使用的語言不熟悉,那么在成本及進(jìn)度估算時必須把學(xué)習(xí)的工作量估算在內(nèi)。一旦確定了軟件需求,待選用的程序設(shè)計語言的技術(shù)特性就顯得非常重要了。如果需要復(fù)雜的數(shù)據(jù)結(jié)構(gòu),就要仔細(xì)衡量有哪些語言能提供這些復(fù)雜的數(shù)據(jù)結(jié)構(gòu)。如果首要的是高性能及實(shí)時處理的能力,則可選用適合于實(shí)時應(yīng)用的語言或效率高的語言。如果該應(yīng)用有許多輸出報告或繁雜的文件處理,最好是根據(jù)軟件的要求,選定一種適合于該項(xiàng)工作的語言。

軟件的設(shè)計質(zhì)量與程序設(shè)計語言的技術(shù)性能無關(guān)(面向?qū)ο笤O(shè)計除外),但在將軟件設(shè)計轉(zhuǎn)化為程序代碼時,轉(zhuǎn)化的質(zhì)量往往受語言性能的影響,因而也會影響到設(shè)計方法。語言的技術(shù)性能對測試和維護(hù)的影響是多種多樣的。例如,直接提供結(jié)構(gòu)化構(gòu)造的語言有利于減少循環(huán)帶來的復(fù)雜性(即McCabe復(fù)雜性),使程序易讀、易測試、易維護(hù)。另一方面,語言的某些技術(shù)特性卻會妨礙測試。例如,在面向?qū)ο蟮恼Z言程序中,由于實(shí)行了數(shù)據(jù)封裝,使得監(jiān)控這些數(shù)據(jù)的執(zhí)行狀態(tài)變得比較困難;由于建立了對象類的繼承結(jié)構(gòu),使得高內(nèi)聚、低耦合的要求受到破壞,增加了測試的困難。此外,只要語言程序的可讀性強(qiáng),而且可以減少程序的復(fù)雜性,這樣的程序設(shè)計語言對于軟件的維護(hù)就是有利的。

總之,通過仔細(xì)地分析和比較,選擇一種功能強(qiáng)而又適用的語言,對成功地實(shí)現(xiàn)從軟件設(shè)計到編碼的轉(zhuǎn)換,提高軟件的質(zhì)量,改善軟件的可測試性和可維護(hù)性是至關(guān)重要的。7.2.3程序設(shè)計語言的選擇

為某個特定開發(fā)項(xiàng)目選擇程序設(shè)計語言時,既要從技術(shù)角度、工程角度、心理學(xué)角度評價和比較各種語言適用程度,又必須考慮現(xiàn)實(shí)可能性,所以有時需要作出某種合理的折中。

有實(shí)際經(jīng)驗(yàn)的軟件開發(fā)人員往往有這樣體會在他們進(jìn)行決策時經(jīng)常面臨的是矛盾的選擇。例如,所有的技術(shù)人員都同意采用某種高級程序設(shè)計語言,但所選擇的計算機(jī)卻沒有這種語言,因此選擇就不切實(shí)際了。在選擇和評價語言時,首先要從問題入手,確定它的要求是什么,這些要求的相對重要性如何。再根據(jù)這些要求和相對重要性來衡量能采用的語言。通常考慮的因素有:

(1)項(xiàng)目的應(yīng)用范圍(最關(guān)鍵);

(2)算法和計算復(fù)雜性;

(3)軟件執(zhí)行的環(huán)境;

(4)性能上的考慮和實(shí)現(xiàn)的條件;

(5)數(shù)據(jù)結(jié)構(gòu)的復(fù)雜性;

(6)軟件開發(fā)人員的知識水平和心理因素等。新的更強(qiáng)有力的語言雖然對于應(yīng)用有很強(qiáng)的吸引力,但是因?yàn)橐延械恼Z言已經(jīng)積累了大量的久經(jīng)使用的程序,具有完整的資料、支撐軟件和軟件開發(fā)工具,程序設(shè)計人員也比較熟悉,而且有過類似項(xiàng)目的開發(fā)經(jīng)驗(yàn)和成功的先例,因此人們往往寧愿選用原有的語種。所以應(yīng)當(dāng)徹底地分析、評價、介紹新的語言,以便從原有語言過渡到新的語言。 7.3結(jié)構(gòu)化程序設(shè)計

結(jié)構(gòu)化程序設(shè)計技術(shù)是20世紀(jì)60年代中期提出來的,它主要包括兩個方面:

(1)在編寫程序時,強(qiáng)調(diào)使用幾種基本控制結(jié)構(gòu),通過組合嵌套,形成程序的控制結(jié)構(gòu)。盡可能避免使用會使程序質(zhì)量受到影響的GOTO語句。

(2)在程序設(shè)計過程中,盡量采用自頂向下和逐步細(xì)化的原則,由粗到細(xì),一步步展開。

采用結(jié)構(gòu)化程序設(shè)計的軟件主要使用面向過程的編程語言。7.3.1結(jié)構(gòu)化程序設(shè)計的原則

(1)使用語言中的順序、選擇、循環(huán)等有限的基本控制結(jié)構(gòu)表示程序邏輯。

(2)選用的控制結(jié)構(gòu)只準(zhǔn)許有一個入口和一個出口。

(3)程序語句組成容易識別的塊,每塊只有一個入口和一個出口。

(4)復(fù)雜結(jié)構(gòu)應(yīng)該用基本控制結(jié)構(gòu)進(jìn)行組合嵌套來實(shí)現(xiàn)。

(5)語言中沒有的控制結(jié)構(gòu),可用一段等價的程序段模擬,但要求該程序段在整個系統(tǒng)中應(yīng)前后一致。

(6)嚴(yán)格控制GOTO語句,僅在用一個非結(jié)構(gòu)化的程序設(shè)計語言去實(shí)現(xiàn)一個結(jié)構(gòu)化的構(gòu)造或者在某種可以改善而不是損害程序可讀性的情況下才可以使用GOTO語句。圖7.1用C語言語句實(shí)現(xiàn)基本控制結(jié)構(gòu)大量采用GOTO語句實(shí)現(xiàn)控制路徑,會使程序路徑變得復(fù)雜而且混亂,因此要控制GOTO語句的使用。但有時完全不用GOTO語句進(jìn)行程序編碼,會比用GOTO語句編出的程序可讀性差。例如,在查找結(jié)束時,文件訪問結(jié)束時,出現(xiàn)錯誤情況要從循環(huán)中轉(zhuǎn)出時,使用布爾變量和條件結(jié)構(gòu)來實(shí)現(xiàn)就不如用GOTO語句來得簡潔易懂。

對于常用的高級程序設(shè)計語言,一般都具備前述的幾種基本控制結(jié)構(gòu)。即使不具備等同的結(jié)構(gòu),也可以采用仿真來實(shí)現(xiàn)。下面以C語言為例進(jìn)行說明,參看圖7.1。圖7.1用C語言語句實(shí)現(xiàn)基本控制結(jié)構(gòu)7.3.2程序設(shè)計——自頂向下,逐步求精

在詳細(xì)設(shè)計和編碼階段,應(yīng)當(dāng)采取自頂向下,逐步求精的方法,把一個模塊的功能逐步分解,細(xì)化為一系列具體的步驟,進(jìn)而翻譯成一系列用某種程序設(shè)計語言寫成的程序。

【案例1】在學(xué)生成績管理部分,可以計算出一個班級學(xué)生某門課的優(yōu)秀率、及格率。根據(jù)需求分析可先寫出一個框架://計算某一班級學(xué)生某門課的優(yōu)秀率、及格率

voidGetStat(學(xué)生成績,返回優(yōu)秀率和及格率)

{ 統(tǒng)計及格學(xué)生數(shù); 統(tǒng)計優(yōu)秀學(xué)生數(shù); 計算及格率; 計算優(yōu)秀率;

}

上述框架中每一個加工語句都可進(jìn)一步細(xì)化://計算某一班級學(xué)生某門課的優(yōu)秀率、及格率

voidGetStat(floatgrade[],intn,float*pass_scale,float*excell_scale)

{ 用pass和excel分別記錄及格學(xué)生數(shù)和優(yōu)秀學(xué)生數(shù);

for(inti=0;i<n;i++)

{ 若grade[i]大于等于90,excel加1; 若grade[i]大于60,pass加1;

}

pass除以n得到及格率;

excel除以n得到優(yōu)秀率;

}

將程序繼續(xù)細(xì)化下去,直到每一個語句都能直接用程序設(shè)計語言來表示為止://計算某一班級學(xué)生某門課的優(yōu)秀率、及格率

voidGetStat(floatgrade[],intn,float*pass_scale,float*excell_scale)

{

intpass=0,excel=0;

for(inti=0;i<n;i++)

{

if(grade[i]>=90)

excel++;

if(grade[i]>60)

pass++;

} *pass_scale=(float)pass/n; *excell_scale=(float)excel/n;

}

自頂向下、逐步求精方法的優(yōu)點(diǎn)是:

(1)自頂向下、逐步求精方法符合人們解決復(fù)雜問題的普遍規(guī)律,可提高軟件開發(fā)的成功率和生產(chǎn)率。

(2)用先全局后局部、先整體后細(xì)節(jié)、先抽象后具體的逐步求精的過程開發(fā)出來的程序具有清晰的層次結(jié)構(gòu),因此程序容易閱讀和理解。

(3)程序自頂向下,逐步細(xì)化,分解成一個樹形結(jié)構(gòu)(如圖7.2所示)。在同一層的結(jié)點(diǎn)上做的細(xì)化工作相互獨(dú)立。若任何一步發(fā)生錯誤,一般只影響它下層的結(jié)點(diǎn),同一層其他結(jié)點(diǎn)不受影響。在以后的測試過程中,也可以先獨(dú)立地一個結(jié)點(diǎn)一個結(jié)點(diǎn)地做,最后再集成。圖7.2學(xué)生成績管理模塊的樹形結(jié)構(gòu)

(4)程序清晰和模塊化,使得在修改和重新設(shè)計一個軟件時,可復(fù)用的代碼量最大。

(5)每一步工作僅需在上層結(jié)點(diǎn)的基礎(chǔ)上做不多的設(shè)計擴(kuò)展即可,便于檢查。

(6)有利于設(shè)計的分工和組織工作。7.3.3數(shù)據(jù)結(jié)構(gòu)的合理化

結(jié)構(gòu)化程序設(shè)計主要是想從程序的控制結(jié)構(gòu)入手,消除不適應(yīng)的、容易引起混亂的GOTO語句。然而這只是問題的一個方面,問題的另一方面是,過去沒有注意到數(shù)據(jù)結(jié)構(gòu)的合理化問題,即數(shù)據(jù)結(jié)構(gòu)訪問的規(guī)范化、標(biāo)準(zhǔn)化問題。

假如數(shù)據(jù)結(jié)構(gòu)中常使用數(shù)組、指針等數(shù)據(jù)類型,則對它們必須采取隨機(jī)訪問,這樣勢必產(chǎn)生訪問上的混亂。例如,要訪問數(shù)組元素A[i][j],必須先對下標(biāo)i,j訪問,造成訪問忽前忽后,這與GOTO語句造成的混亂類似,同樣是有害的。解決這一問題的辦法是用棧和隊列去代替數(shù)組和指針。棧與隊列分別是按后進(jìn)先出(LIFO)和先進(jìn)先出(FIFO)的原則進(jìn)行存取的。在程序中用棧和隊列代替數(shù)組和指針,用合理、規(guī)范的順序存取代替隨機(jī)存取,將克服隨機(jī)存取帶來的麻煩。而且有人證明,所有使用數(shù)組和指針的程序,都可以使用棧和隊列的程序等價替換。 7.4編碼風(fēng)格

在軟件生存期中,人們經(jīng)常要閱讀程序。特別是在軟件測試階段和維護(hù)階段,編寫程序的人與參與測試、維護(hù)的人都要閱讀程序。因此,閱讀程序是軟件開發(fā)和維護(hù)過程中一個重要組成部分,而且讀程序的時間比寫程序的時間還要多。20世紀(jì)70年代初,有人提出在編寫程序時,應(yīng)使程序具有良好的風(fēng)格,力圖從編碼原則的角度提高程序的可讀性,改善程序質(zhì)量。從此,編碼風(fēng)格便成了程序設(shè)計中必不可少的一部分了。

程序設(shè)計風(fēng)格包括4個方面:源程序文檔化、數(shù)據(jù)說明、語句結(jié)構(gòu)和輸入/輸出方法。7.4.1程序的內(nèi)部文檔

1.符號名的命名

符號名即標(biāo)識符,包括模塊名、變量名、常量名、子程序名、數(shù)據(jù)區(qū)名、緩沖區(qū)名等。對于標(biāo)識符的命名一般有如下要求:

(1)標(biāo)識符的命名要清晰、明了,有一定的實(shí)際意義,同時使用完整的單詞或大家基本可以理解的縮寫,避免使人產(chǎn)生誤解。

較短的單詞可通過去掉“元音”形成縮寫;較長的單詞可取單詞的頭幾個字母形成縮寫;一些單詞有大家公認(rèn)的縮寫。例如,以下單詞的縮寫能夠被大家基本認(rèn)可:

temp可縮寫為tmp;

flag可縮寫為flg;

statistic可縮寫為stat;

increment可縮寫為inc;

message可縮寫為msg。

(2)命名中若使用特殊約定或縮寫,則要有注釋說明。應(yīng)該在源文件的開始處對文件中所使用的縮寫或約定,特別是特殊的縮寫,進(jìn)行必要的注釋說明。

(3)自己特有的命名風(fēng)格,要自始至終保持一致,不可來回變化。個人的命名風(fēng)格,在符合所在項(xiàng)目組或產(chǎn)品組的命名規(guī)則的前提下,才可使用(即命名規(guī)則中沒有規(guī)定到的地方才可有個人命名風(fēng)格)。

(4)對于變量命名,盡量不要取單個字符(如i、j、k等),建議除了要有具體含義外,還要能表明其變量類型、數(shù)據(jù)類型等,但i、j、k作局部循環(huán)變量是允許的。

變量,尤其是局部變量,如果用單個字符表示,很容易敲錯(如i寫成j),而編譯時又檢查不出來,有可能為了這個小小的錯誤而花費(fèi)大量的查錯時間。

例如:下面所示的局部變量名的定義方法可以借鑒。

intliv_Width

其變量名解釋如下:

l

局部變量(Local)

(其他:g

全局變量(Global)...)

i

數(shù)據(jù)類型(Interger)

v

變量(Variable)

(其他:c

常量(Const)...)

Width

變量含義

這樣可以防止局部變量與全局變量重名。

(5)命名規(guī)范必須與所使用的系統(tǒng)風(fēng)格保持一致,并在同一項(xiàng)目中統(tǒng)一。比如采用UNIX的全小寫加下劃線的風(fēng)格或大小寫混排的方式,則不要使用大小寫與下劃線混排的方式;用作特殊標(biāo)識,如標(biāo)識成員變量或全局變量的m_和g_,其后加上大小寫混排的方式是允許的。

示例:Add_User不允許,add_user、AddUser、m_AddUser允許。

(6)名字不是越長越好,過長的名字會使程序的邏輯流程變得模糊,給修改帶來困難。所以應(yīng)當(dāng)選擇精煉的、意義明確的名字,改善對程序功能的理解。

(7)在一個程序中,一個變量只應(yīng)用于一種用途。也就是說,在同一個程序中一個變量不能身兼幾種工作。

(8)除非必要,不要用數(shù)字或較奇怪的字符來定義標(biāo)識符。

例如,如下命名,使人產(chǎn)生疑惑:

#define_EXAMPLE_0_TEST_

#define_EXAMPLE_1_TEST_

voidset_sls00(BYTEsls);

應(yīng)改為有意義的單詞命名

#define_EXAMPLE_UNIT_TEST_

#define_EXAMPLE_ASSERT_TEST_

voidset_udt_msg_sls(BYTEsls);

(9)在同一軟件產(chǎn)品內(nèi),應(yīng)規(guī)劃好接口部分的標(biāo)識符(變量、結(jié)構(gòu)、函數(shù)及常量)的命名,防止編譯、鏈接時產(chǎn)生沖突。對接口部分的標(biāo)識符應(yīng)該有更嚴(yán)格的限制,防止沖突。例如,可規(guī)定接口部分的變量與常量之前加上“模塊”標(biāo)識等。

(10)用正確的反義詞組命名具有互斥意義的變量或相反動作的函數(shù)等。下面是一些在軟件中常用的反義詞組。

add/remove

begin/end

create/destroy

insert/delete

first/last

get/release

add/delete

lock/unlock

open/close

min/max

old/new

start/stop

next/previous

source/target

show/hide

put/get increment/decrement

send/receive

source/destination

cut/paste

up/down

示例:

int

min_sum;

int

max_sum;

int

add_user(char*user_name);

intdelete_user(char*user_name);

2.程序的注釋

夾在程序中的注釋是程序員與日后的程序讀者之間通信的重要手段。正確的注釋能夠幫助讀者理解程序,可為后續(xù)階段進(jìn)行測試和維護(hù)提供明確的指導(dǎo)。因此,注釋決不是可有可無的。大多數(shù)程序設(shè)計語言允許使用自然語言來寫注釋,這就給閱讀程序帶來了很大的方便。

(1)一般情況下,源程序的有效注釋量必須在20%以上。注釋的原則是有助于對程序的閱讀理解,在該加的地方都加上。注釋不宜太多也不能太少,注釋語言必須準(zhǔn)確、易懂、簡潔。

(2)說明性文件(如?.h文件、.inc文件、.def文件、編譯說明文件?.cfg等)頭部應(yīng)進(jìn)行注釋,注釋應(yīng)列出版權(quán)說明、版本號、生成日期、作者、內(nèi)容、功能、與其他文件的關(guān)系、修改日志等,頭文件的注釋中還應(yīng)有函數(shù)功能簡要說明。

下面是一段頭文件的頭部注釋。當(dāng)然,實(shí)際的注釋并不局限于此格式,但上述信息建議要包含在內(nèi)。

(3)源文件頭部應(yīng)進(jìn)行注釋,應(yīng)列出版權(quán)說明、版本號、生成日期、作者、模塊目的/功能、主要函數(shù)及其功能、修改日志等。

示例:下面是一段源文件的頭部注釋。當(dāng)然,實(shí)際的注釋并不局限于此格式,但上述信息建議要包含在內(nèi)。

/********************************************************

Copyright(C),1988-1999,******Tech.Co.,Ltd.

FileName:test.cpp

Author:

Version:

Date:

Description:

//模塊描述

Version:

//版本信息

FunctionList:

//主要函數(shù)及其功能

1.-------

History:

//歷史修改記錄

<author>

<time>

<version>

<desc>

David

96/10/12

1.0

buildthismoudle

******************************************************/說明:Description一項(xiàng)描述本文件的內(nèi)容、功能、內(nèi)部各部分之間的關(guān)系及本文件與其他文件的關(guān)系等。History是修改歷史記錄列表,每條修改記錄應(yīng)包括修改日期、修改者及修改內(nèi)容簡述。

(4)函數(shù)頭部應(yīng)進(jìn)行注釋,列出函數(shù)的目的/功能、輸入?yún)?shù)、輸出參數(shù)、返回值、調(diào)用關(guān)系(函數(shù)、表)等。

示例:下面是一段函數(shù)的注釋。當(dāng)然,實(shí)際的注釋并不局限于此格式,但上述信息建議要包含在內(nèi)。

/*************************************************

Function:

//函數(shù)名稱

Description:

//函數(shù)功能、性能等的描述

Calls:

//被本函數(shù)調(diào)用的函數(shù)清單

CalledBy:

//調(diào)用本函數(shù)的函數(shù)清單

TableAccessed://被訪問的表(此項(xiàng)僅對于牽扯到數(shù)據(jù)庫操作的程序)

TableUpdated:

//被修改的表(此項(xiàng)僅對于牽扯到數(shù)據(jù)庫操作的程序)

Input:

//輸入?yún)?shù)說明,包括每個參數(shù)的作用、取值說明及參數(shù)間關(guān)系

Output:

//對輸出參數(shù)的說明

Return:

//函數(shù)返回值的說明

Others:

//其他說明

*************************************************/

(5)邊寫代碼邊注釋,修改代碼的同時要修改相應(yīng)的注釋,以保證注釋與代碼的一致性。不再有用的注釋要刪除。

(6)注釋的內(nèi)容要清楚、明了,含義準(zhǔn)確,防止注釋二義性。

(7)避免在注釋中使用縮寫,特別是非常用縮寫。在使用縮寫時或使用縮寫之前,應(yīng)對縮寫進(jìn)行必要的說明。

注釋應(yīng)與其描述的代碼相近,對代碼的注釋應(yīng)放在其上方或右方(對單條語句的注釋)相鄰位置,不可放在下面,如放于上方則需與其上面的代碼用空行隔開。示例,如下例子不符合規(guī)范:

repssn_ind=ssn_data[index].repssn_index;

repssn_ni=ssn_data[index].ni;

/*getreplicatesubsystemindexandnetindicator*/

應(yīng)寫為:

/*getreplicatesubsystemindexandnetindicator*/

repssn_ind=ssn_data[index].repssn_index;

repssn_ni=ssn_data[index].ni;

(8)對于所有有物理含義的變量、常量,如果其命名不是充分自注釋的,在聲明時都必須加以注釋,說明其物理含義。變量、常量、宏的注釋應(yīng)放在其上方相鄰位置或右方。

示例:

/*activestatistictasknumber*/

#defineMAX_ACT_TASK_NUMBER1000

#defineMAX_ACT_TASK_NUMBER1000/*activestatistictasknumber*/

(9)數(shù)據(jù)結(jié)構(gòu)(包括數(shù)組、結(jié)構(gòu)、類、枚舉等)聲明中,如果各結(jié)構(gòu)的命名不是充分自注釋的,必須加以注釋。對數(shù)據(jù)結(jié)構(gòu)的注釋應(yīng)放在其上方相鄰位置,不可放在下面;對結(jié)構(gòu)中的每個域的注釋放在此域的右方。

示例,可按如下形式說明枚舉/數(shù)據(jù)/聯(lián)合結(jié)構(gòu):

/*sccpinterfacewithsccpuserprimitivemessagename*/

enum

SCCP_USER_PRIMITIVE

{

N_UNITDATA_IND,/*sccpnotifysccpuserunitdatacome*/

N_NOTICE_IND,

/*sccpnotifyusertheNo.7networkcannot*/

/*transmissionthismessage*/

N_UNITDATA_REQ, /*sccpuser'sunitdatatransmissionrequest*/

};

(10)全局變量要有較詳細(xì)的注釋,包括對其功能、取值范圍、哪些函數(shù)或過程存取它以及存取時的注意事項(xiàng)等說明。

示例:

/*TheErrorCodewhenSCCPtranslate*/

/*GlobalTitlefailure,asfollows*/

//變量作用、含義

/*0-SUCCESS

1-GTTableerror*/

/*2-GTerror

Others-nouse

*/

//變量取值范圍

/*only

function

SCCPTranslate()in*/

/*thismodualcanmodifyit,

and

other*/

/*modulecanvisititthroughcall*/

/*the

functionGetGTTransErrorCode()*/

//使用方法

BYTEg_GTTranErrorCode;

(11)注釋與所描述內(nèi)容進(jìn)行同樣的縮排。

說明:可使程序排版整齊,并方便注釋的閱讀與理解。

示例:如下例子,排版不整齊,閱讀稍感不方便。

voidexample_fun(void)

{

/*codeonecomments*/

CodeBlockOne

/*codetwocomments*/

CodeBlockTwo

}應(yīng)改為如下布局:

voidexample_fun(void)

{

/*codeonecomments*/

CodeBlockOne

/*codetwocomments*/

CodeBlockTwo

}

(12)將注釋與其上面的代碼用空行隔開。

示例:如下例子,顯得代碼過于緊湊。

/*codeonecomments*/

programcodeone

/*codetwocomments*/

programcodetwo

應(yīng)書寫如下:

/*codeonecomments*/

programcodeone

/*codetwocomments*/

programcodetwo

(13)對變量的定義和分支語句(條件分支、循環(huán)語句等)必須編寫注釋。

說明:這些語句往往是程序?qū)崿F(xiàn)某一特定功能的關(guān)鍵,對于維護(hù)人員來說,良好的注釋能幫助更好地理解程序,有時甚至優(yōu)于看設(shè)計文檔。

(14)避免在一行代碼或表達(dá)式的中間插入注釋。

說明:除非必要,不應(yīng)在代碼或表達(dá)式中間插入注釋,否則容易使代碼的可理解性變差。

(15)通過對函數(shù)或過程、變量、結(jié)構(gòu)等的正確命名以及代碼結(jié)構(gòu)的合理組織,使代碼成為自注釋的。

說明:清晰準(zhǔn)確的函數(shù)、變量等的命名,可增加代碼可讀性,減少不必要的注釋。

(16)在代碼的功能、意圖層次上進(jìn)行注釋,提供有用的、額外的信息。

說明:注釋的目的是解釋代碼的目的、功能和采用的方法,提供代碼以外的信息,幫助讀者理解代碼,防止不必要地重復(fù)注釋信息。

示例:如下注釋意義不大。

/*ifreceive_flagisTRUE*/

if(receive_flag)

而如下的注釋則給出了額外有用的信息:

/*ifmtpreceiveamessagefromlinks*/

if(receive_flag)

(17)在程序塊的結(jié)束行右方加注釋標(biāo)記,以表明某程序塊的結(jié)束。

說明:當(dāng)代碼段較長,特別是有多重嵌套時,這樣做可以使代碼更清晰,更便于閱讀。

示例:參見如下例子。

if(...)

{

//programcode

while(index<MAX_INDEX)

{

//programcode

}/*endofwhile(index<MAX_INDEX)*/ //指明該條while語句結(jié)束

}/*endof

if(...)*/ //指明是哪條if語句結(jié)束

(18)注釋格式盡量統(tǒng)一,建議使用“/*…*/”。

(19)注釋應(yīng)考慮程序易讀及外觀排版的因素,使用的語言若是中、英文兼有,建議多使用中文,除非能用非常流利準(zhǔn)確的英文表達(dá)。注釋語言不統(tǒng)一,影響程序易讀性和外觀排版。出于對維護(hù)人員的考慮,建議使用中文。

3.視覺組織

利用空格、空行和移行,可提高程序的可視化程度。

(1)恰當(dāng)?shù)乩每崭?,可以突出運(yùn)算的優(yōu)先性,避免發(fā)生運(yùn)算的錯誤。

(2)自然的程序段之間可用空行隔開。

(3)對于選擇語句和循環(huán)語句,把其中的程序段語句向右做階梯式移行,這樣可使程序的邏輯結(jié)構(gòu)更加清晰,層次更加分明。7.4.2數(shù)據(jù)說明

在編寫程序時,需注意數(shù)據(jù)說明的風(fēng)格。為了使程序中的數(shù)據(jù)說明更易于理解和維護(hù),必須注意以下幾點(diǎn):

(1)數(shù)據(jù)說明的次序應(yīng)當(dāng)規(guī)范化,使數(shù)據(jù)屬性容易查找。

(2)當(dāng)多個變量名用一個語句說明時,應(yīng)當(dāng)對這些變量按字母的順序進(jìn)行排列。

(3)如果設(shè)計了一個復(fù)雜的數(shù)據(jù)結(jié)構(gòu),應(yīng)當(dāng)使用注釋來說明在程序?qū)崿F(xiàn)時這個數(shù)據(jù)結(jié)構(gòu)的固有特點(diǎn)。7.4.3語句結(jié)構(gòu)

在設(shè)計階段確定了軟件的邏輯結(jié)構(gòu),構(gòu)造單個語句則是編碼階段的任務(wù)。語句構(gòu)造力求簡單、直接,不能為了片面追求效率而使語句復(fù)雜化。

編碼中對語句的編寫應(yīng)遵循以下原則:

(1)在一行內(nèi)只寫一條語句,并且采取適當(dāng)?shù)囊菩懈袷剑钩绦虻倪壿嫼凸δ茏兊酶用鞔_。

(2)盡量用公共過程或子程序去代替重復(fù)的功能代碼段。

(3)使用括號來清晰地表達(dá)算術(shù)表達(dá)式和邏輯表達(dá)式的運(yùn)算順序。

(4)避免不必要的轉(zhuǎn)移。如果能保持程序的可讀性,則不必用GOTO語句。

(5)盡量只采用三種基本的控制結(jié)構(gòu)來編寫程序。

(6)避免采用過于復(fù)雜的判定條件。

(7)盡量減少使用“否定”條件的條件語句,不要讓讀者繞彎子想。

(8)避免過多的循環(huán)嵌套和條件嵌套。

(9)不要使GOTO語句相互交叉。

(10)避免循環(huán)的多個出口。

(11)使用數(shù)組,以避免重復(fù)的控制序列。

(12)對遞歸定義的數(shù)據(jù)結(jié)構(gòu)盡量使用遞歸過程。

(13)注意計算機(jī)浮點(diǎn)數(shù)運(yùn)算的特點(diǎn),例如,浮點(diǎn)數(shù)運(yùn)算10.0?×?0.1通常不等于1.0。

(14)不要單獨(dú)進(jìn)行浮點(diǎn)數(shù)的比較。用它們做比較,其結(jié)果常常發(fā)生異常情況。

(15)在程序中應(yīng)有出錯處理功能,一旦出現(xiàn)故障,不要讓操作系統(tǒng)進(jìn)行干預(yù),導(dǎo)致停工。7.4.4輸入和輸出

輸入和輸出信息是與用戶的使用直接相關(guān)的。輸入和輸出的方式和格式應(yīng)當(dāng)盡可能方便用戶的使用。因此,在軟件需求分析階段和設(shè)計階段,就應(yīng)基本確定輸入和輸出的風(fēng)格。系統(tǒng)能否被用戶接受,有時就取決于輸入和輸出的風(fēng)格。

不論是批處理的輸入/輸出方式,還是交互式的輸入/輸出方式,在設(shè)計和程序編碼時都應(yīng)考慮下列原則:

(1)對所有的輸入數(shù)據(jù)都進(jìn)行檢驗(yàn),從而識別錯誤的輸入,以保證每個數(shù)據(jù)的有效性。

(2)檢查輸入項(xiàng)的各種重要組合的合理性,必要時報告輸入狀態(tài)信息。

(3)使輸入的步驟和操作盡可能簡單,并保持簡單的輸入格式。

(4)輸入數(shù)據(jù)時,應(yīng)允許使用自由格式輸入。

(5)應(yīng)允許缺省值。

(6)輸入一批數(shù)據(jù)時,最好使用輸入結(jié)束標(biāo)志,而不要由用戶指定輸入數(shù)據(jù)數(shù)目。

(7)在以交互式輸入/輸出方式進(jìn)行輸入時,要在屏幕上使用提示符明確提示交互輸入的請求,指明可使用選擇項(xiàng)的種類和取值范圍。同時,在數(shù)據(jù)輸入的過程中和輸入結(jié)束時,也要在屏幕上給出狀態(tài)信息。

(8)當(dāng)程序設(shè)計語言對輸入/輸出格式有嚴(yán)格要求時,應(yīng)保持輸入格式與輸入語句要求的一致性。

(9)給所有的輸出加注解,并設(shè)計輸出報表格式。輸入/輸出風(fēng)格還受到許多其他因素的影響。如輸入/輸出設(shè)備(例如終端的類型、圖形設(shè)備、數(shù)字化轉(zhuǎn)換設(shè)備等)、用戶的熟練程度以及通信環(huán)境等。

Wasserman為“用戶軟件工程及交互系統(tǒng)的設(shè)計”提供了以下一組指導(dǎo)性原則,可供軟件設(shè)計和編程參考。

(1)把計算機(jī)系統(tǒng)的內(nèi)部特性隱蔽起來不讓用戶看到。

(2)有完備的輸入出錯檢查和出錯恢復(fù)措施,在程序執(zhí)行過程中盡量排除由于用戶的原因而造成程序出錯的可能性。

(3)如果用戶的請求有了結(jié)果,應(yīng)隨時通知用戶。

(4)充分利用聯(lián)機(jī)幫助手段。對于不熟練的用戶,提供對話式服務(wù);對于熟練的用戶,提供較高級的系統(tǒng)服務(wù),改善輸入/輸出的能力。

(5)使輸入格式和操作要求與用戶的技術(shù)水平相適應(yīng)。對于不熟練的用戶,充分利用菜單系統(tǒng)逐步引導(dǎo)用戶操作;對于熟練的用戶,允許繞過菜單,直接使用命令方式進(jìn)行操作。

(6)按照輸出設(shè)備的速度設(shè)計信息輸出過程。

(7)區(qū)別不同類型的用戶,分別進(jìn)行設(shè)計和編碼。

(8)保持始終如一的響應(yīng)時間。

(9)在出現(xiàn)錯誤時應(yīng)盡量減少用戶的額外工作。 7.5程序編碼優(yōu)化技術(shù)

7.5.1程序優(yōu)化

1.討論效率的準(zhǔn)則

程序的效率是指程序的執(zhí)行速度及程序所需占用的內(nèi)存的存儲空間。討論程序效率的幾條準(zhǔn)則為:

(1)效率是一個性能要求,應(yīng)當(dāng)在需求分析階段給出。軟件效率以需求為準(zhǔn),不應(yīng)以人力所及為準(zhǔn)。

(2)好的設(shè)計可以提高效率。

(3)程序的效率與程序的簡單性相關(guān)。

2.算法對效率的影響

源程序的效率與詳細(xì)設(shè)計階段確定的算法的效率直接相關(guān)。在詳細(xì)設(shè)計轉(zhuǎn)換成源程序代碼后,算法效率反映為程序的執(zhí)行速度和對存儲容量的要求。

轉(zhuǎn)換過程中的指導(dǎo)原則是:

(1)在編寫程序前,盡可能化簡有關(guān)的算術(shù)表達(dá)式和邏輯表達(dá)式。

(2)仔細(xì)檢查算法中嵌套的循環(huán),盡可能將某些語句或表達(dá)式移到循環(huán)外面。

(3)盡量避免使用多維數(shù)組。

(4)盡量避免使用指針和復(fù)雜的表。

(5)采用“快速”的算術(shù)運(yùn)算。

(6)不要混淆數(shù)據(jù)類型,避免在表達(dá)式中出現(xiàn)類型混雜。

(7)盡量采用整數(shù)算術(shù)表達(dá)式和布爾表達(dá)式。

(8)選用等效的高效率算法。

許多編譯程序具有“優(yōu)化”功能,可以自動生成高效率的目標(biāo)代碼。它可剔除重復(fù)的表達(dá)式計算,采用循環(huán)求值法、快速的算術(shù)運(yùn)算以及一些能夠提高目標(biāo)代碼運(yùn)行效率的算法來提高效率。對于效率至上的應(yīng)用來說,這樣的編譯程序是很有效的。

3.影響存儲效率的因素

在大中型計算機(jī)系統(tǒng)中,存儲限制不再是主要問題。在這種環(huán)境下,對內(nèi)存采取基于操作系統(tǒng)的分頁功能的虛擬存儲管理,給軟件提供了巨大的邏輯地址空間。這時,存儲效率與操作系統(tǒng)的分頁功能直接相關(guān),但并不是指要使所使用的存儲空間達(dá)到最少。

采用結(jié)構(gòu)化程序設(shè)計,將程序功能合理分塊,使每個模塊或一組密切相關(guān)模塊的程序體積大小與每頁的容量相匹配,可減少頁面調(diào)度,減少內(nèi)外存交換,提高存儲效率。

在微型計算機(jī)系統(tǒng)中,存儲容量對軟件設(shè)計和編碼的制約很大,因此要選擇可生成較短目標(biāo)代碼且存儲壓縮性能優(yōu)良的編譯程序,有時需采用匯編程序。通過程序員富有創(chuàng)造性的努力,提高軟件時間與空間效率。

4.影響輸入/輸出的因素

輸入/輸出可分為兩種類型:一種是面向人(操作員)的輸入/輸出;一種是面向設(shè)備的輸入/輸出。如果操作員能夠十分方便、簡單地錄入輸入數(shù)據(jù),或者能夠十分直觀、一目了然地了解輸出信息,則可以說面向人的輸入/輸出是高效的。至于面向設(shè)備的輸入/輸出,分析起來比較復(fù)雜。從詳細(xì)設(shè)計和程序編碼的角度來說,可以提出一些提高輸入/輸出效率的指導(dǎo)原則:

(1)輸入/輸出的請求應(yīng)當(dāng)最小化。

(2)對于所有的輸入/輸出操作,應(yīng)安排適當(dāng)?shù)木彌_區(qū),以減少頻繁的信息交換。

(3)對輔助存儲(例如磁盤),應(yīng)選擇盡可能簡單的、可接受的存取方法。

(4)對輔助存儲的輸入/輸出,應(yīng)當(dāng)成塊傳送。

(5)對終端或打印機(jī)的輸入/輸出,應(yīng)考慮設(shè)備特性,盡可能改善輸入/輸出的質(zhì)量和速度。

(6)任何不易理解的、對改善輸入/輸出效果關(guān)系不大的措施都是不可取的。

(7)任何不易理解的所謂“超高效”的輸入/輸出都是毫無價值的。

(8)好的輸入/輸出程序設(shè)計風(fēng)格對提高輸入/輸出效率會有明顯的效果。7.5.2程序優(yōu)化方法

1.選擇合適的數(shù)據(jù)結(jié)構(gòu)

選擇一種合適的數(shù)據(jù)結(jié)構(gòu)很重要,如果在一堆隨機(jī)存放的數(shù)據(jù)中使用了大量的插入和刪除指令,那么使用鏈表要快得多。

數(shù)組與指針語句具有十分密切的關(guān)系,一般來說,指針比較靈活簡潔,而數(shù)組則比較直觀,容易理解。對于大部分的編譯器,使用指針比使用數(shù)組生成的代碼更短,執(zhí)行效率更高。在許多情況下,可以用指針運(yùn)算代替數(shù)組索引,這樣做常常能產(chǎn)生又快又短的代碼。與數(shù)組索引相比,指針一般能使代碼速度更快,占用空間更少。使用多維數(shù)組時差異更明顯。下面的代碼作用是相同的,但是效率不一樣。數(shù)組索引

for(;;)

{

A=array[t++];

...

}

指針運(yùn)算

p=array;

for(;;)

{

a=*(p++);

...

}

2.對變量進(jìn)行優(yōu)化

(1)按數(shù)據(jù)類型的長度排序本地變量。當(dāng)編譯器分配給本地變量空間時,它們的順序和它們在源代碼中聲明的順序一樣。應(yīng)該把長的變量放在短的變量前面。如果第一個變量對齊了,其他變量就會連續(xù)地存放,而且不用填充字節(jié)自然就會對齊。有些編譯器在分配變量時不會自動改變變量順序,有些編譯器不能產(chǎn)生四字節(jié)對齊的棧,所以四字節(jié)可能不對齊。下面這個例子演示了本地變量聲明的重新排序:不好的代碼,普通順序:

shortga,gu,gi;

longfoo,bar;

doublex,y,z[3];

chara,b;

floatbaz;推薦的代碼,改進(jìn)的順序:

doublez[3];

doublex,y;

longfoo,bar;

floatbaz;

shortga,gu,gi;

chara,b;

(2)把頻繁使用的指針型參數(shù)拷貝到本地變量。避免在函數(shù)中頻繁使用指針型參數(shù)指向的值。因?yàn)榫幾g器不知道指針之間是否存在沖突,所以指針型參數(shù)往往不能被編譯器優(yōu)化。這樣數(shù)據(jù)就不能被存放在寄存器中,而且明顯占用了內(nèi)存帶寬。請在函數(shù)一開始就把指針指向的數(shù)據(jù)保存到本地變量。如果需要的話,在函數(shù)結(jié)束前拷貝回去。不好的代碼:

//假設(shè)q!=r

voidisqrt(unsignedlonga,unsignedlong*q,unsignedlong*r)

{

*q=a;

if(a>0)

{

while(*q>(*r=a/*q))

{

*q=(*q+*r)>>1;

}

}

*r=a-*q**q;

}推薦的代碼:

//假設(shè)q!=r

voidisqrt(unsignedlonga,unsignedlong*q,unsignedlong*r)

{

unsignedlongqq,rr;

qq=a;

if(a>0)

{

while(qq>(rr=a/qq))

{

qq=(qq+rr)>>1;

}

}

rr=a-qq*qq;

*q=qq;

*r=rr;

}

3.使結(jié)構(gòu)體成員布局良好

結(jié)構(gòu)體變量在存儲時需要使其成員雙字或四字對齊。很多編譯器有“使結(jié)構(gòu)體字、雙字或四字對齊”的選項(xiàng),但是,還是需要改善結(jié)構(gòu)體成員的對齊。有些編譯器可能分配給結(jié)構(gòu)體成員空間的順序與它們聲明的不同。但是,有些編譯器并不提供這些功能或者效果不好。所以,要在付出最小代價的情況下實(shí)現(xiàn)最好的結(jié)構(gòu)體和結(jié)構(gòu)體成員對齊,建議采取下列方法:

(1)按數(shù)據(jù)類型的長度排序。把結(jié)構(gòu)體的成員按照它們的類型長度排序,聲明成員時把長的類型放在短的前面。編譯器要求把長型數(shù)據(jù)類型存放在偶數(shù)地址邊界。在申明一個復(fù)雜的數(shù)據(jù)類型(既有多字節(jié)數(shù)據(jù)又有單字節(jié)數(shù)據(jù))時,應(yīng)該首先存放多字節(jié)數(shù)據(jù),然后再存放單字節(jié)數(shù)據(jù),這樣可以避免內(nèi)存的空洞。編譯器自動地把結(jié)構(gòu)體變量對齊在內(nèi)存的偶數(shù)邊界。

(2)把結(jié)構(gòu)體填充成最長類型長度的整倍數(shù)。這樣,如果結(jié)構(gòu)體的第一個成員對齊了,整個結(jié)構(gòu)體自然也就對齊了。下面的例子演示了如何對結(jié)構(gòu)體成員進(jìn)行重新排序。

不好的代碼,普通順序:

struct

{

chara[5];

longk;

doublex;

}baz;推薦的代碼,改變了順序并手動填充了幾個字節(jié):

struct

{

doublex;

longk;

chara[5];

charpad[7];

}baz;

這個規(guī)則同樣適用于類的成員的布局。

4.分支結(jié)構(gòu)的優(yōu)化

在if結(jié)構(gòu)中如果要判斷的并列條件較多,最好將它們拆分成多個if結(jié)構(gòu),然后嵌套在一起,這樣可以避免無謂的判斷。優(yōu)化前的代碼:

if(a>b&&a<c)

else

if(a>b&&a>=c)

else

if(a<=b&&a<c)

else

…優(yōu)化后的代碼:

if(a>b)

if(a<c)

else

else

if(a<=b&&a<c)

else

5.減少運(yùn)算的強(qiáng)度

(1)查表。對于在程序中頻繁計算的數(shù)據(jù),可以使用查表的方法來得到。即,先計算出可能使用到的數(shù)據(jù),保存在一個數(shù)據(jù)表中,待以后使用時再查找??聪旅娴睦樱?/p>

舊代碼:

longfactorial(inti)

{

if(i==0)

return1;

else

returni*factorial(i-1);

}新代碼:

staticlongfactorial_table[]={1,1,2,6,24,120,720/*etc*/};

longfactorial(inti)

{

returnfactorial_table[i];

}

如果表很大,不好寫,就寫一個init函數(shù),在循環(huán)外臨時生成表格。

(2)求余運(yùn)算。

a=a%8;

可以改為:

a=a&7;

說明:位操作只需一個指令周期即可完成,而大部分編譯器的“%”運(yùn)算是調(diào)用子程序來完成的,代碼長、執(zhí)行速度慢。通常,只要是求2n的余數(shù),均可使用位操作的方法來代替。

(3)平方運(yùn)算。

a=pow(a,2.0);

可以改為:

a=a*a;

說明:在有內(nèi)置硬件乘法器的處理器中,乘法運(yùn)算比求平方運(yùn)算快得多,因?yàn)楦↑c(diǎn)數(shù)的求平方是通過調(diào)用子程序來實(shí)現(xiàn)的。在具有硬件乘法器的處理器中,乘法運(yùn)算只需2個時鐘周期就可以完成。即使沒有內(nèi)置硬件乘法器,乘法運(yùn)算的子程序也比平方運(yùn)算的子程序代碼短,執(zhí)行速度快。

(4)用移位實(shí)現(xiàn)乘除法運(yùn)算。

a=a*4;

b=b/4;

可以改為:

a=a<<2;

b=b>>2;

通常如果需要乘以或除以2n,都可以用移位的方法代替。用移位的方法實(shí)現(xiàn)乘除運(yùn)算比直接用乘除法的代碼效率高。實(shí)際上,只要是乘以或除以一個整數(shù),均可以用移位的方法得到結(jié)果。如:

a=a*9

可以改為:

a=(a<<3)+a采用運(yùn)算量更小的表達(dá)式替換原來的表達(dá)式,下面是一個經(jīng)典例子:舊代碼:

x=w%8;

y=pow(x,2.0);

z=y*33;

for(i=0;i<MAX;i++)

{

h=14*i;

printf("%d",h);

}

新代碼:

x=w&7;/*位操作比求余運(yùn)算快*/

y=x*x;/*乘法比平方運(yùn)算快*/

z=(y<<5)+y;/*位移乘法比乘法快*/

for(i=h=0;i<MAX;i++)

{

h+=14;/*加法比乘法快*/

printf("%d",h);

}

(5)避免不必要的整數(shù)除法。整數(shù)除法是整數(shù)運(yùn)算中最慢的,所以應(yīng)該盡可能避免。一種可能減少整數(shù)除法的地方是連除,這里的除法可以由乘法代替。這個替換的副作用是有可能在算乘積時會溢出,所以只能在一定范圍的除法中使用。不好的代碼:

inti,j,k,m;

m=i/j/k;

推薦的代碼:inti,j,k,m;m=i/(j*k);

(6)使用增量和減量操作符。在使用加一和減一操作時盡量使用增量和減量操作符,因?yàn)樵?、減量符語句比賦值語句更快,原因在于對大多數(shù)CPU來說,對內(nèi)存字的增、減量操作不必明顯地使用取內(nèi)存和寫內(nèi)存的指令。比如下面這條語句:

x=x+1;

模仿大多數(shù)微機(jī)匯編語言,產(chǎn)生的代碼類似于:

moveA,x ;把x從內(nèi)存取出存入累加器A

addA,1 ;累加器A加1

storex ;把新值存回x如果使用增量操作符,生成的代碼如下:

incrx ;?x加1

顯然,采用增、減量符語句不用取指令和存指令,這樣執(zhí)行的速度加快,同時指令的長度也縮短了。

(7)使用復(fù)合賦值表達(dá)式。復(fù)合賦值表達(dá)式(如a-=1及a+=1等)能夠生成高質(zhì)量的程序代碼。

(8)提取公共的子表達(dá)式。在某些情況下,編譯器不能從浮點(diǎn)表達(dá)式中提取公共的子表達(dá)式,因?yàn)檫@意味著對表達(dá)式重新排序。需要特別指出的是,編譯器在提取公共子表

達(dá)式前不能按照代數(shù)的等價關(guān)系重新安排表達(dá)式。這時,程序員要手動地提取公共的子表達(dá)式。不好的代碼:

floata,b,c,d,e,f;

e=b*c/d;

f=b/d*a;

推薦的代碼:

floata,b,c,d,e,f;

constfloatt(b/d);

e=c*t;

f=a*t;

不好的代碼:

floata,b,c,d,e,f;

e=a/c;

f=b/c;

推薦的代碼:

floata,b,c,d,e,f;

constfloatt(1.0f/c);

e=a*t;

f=b*t;

f=a*t;

6.循環(huán)優(yōu)化

(1)充分分解小的循環(huán)。要充分利用CPU的指令緩存,就要充分分解小的循環(huán)。特別是當(dāng)循環(huán)體本身很小的時候,分解循環(huán)可以提高性能。

優(yōu)化前的代碼:

//3D轉(zhuǎn)化:把矢量V和4?×?4矩陣M相乘

for(i=0;i<4;i++)

{

r[i]=0;

for(j=0;j<4;j++)

{

r[i]+=M[j][i]*V[j];

}

}推薦的代碼:

r[0]=M[0][0]*V[0]+M[1][0]*V[1]+M[2][0]*V[2]+M[3][0]*V[3];

r[1]=M[0][1]*V[0]+M[1][1]*V[1]+M[2][1]*V[2]+M[3][1]*V[3];

r[2]=M[0][2]*V[0]+M[1][2]*V[1]+M[2][2]*V[2]+M[3][2]*V[3];

r[3]=M[0][3]*V[0]+M[1][3]*V[1]+M[2][3]*V[2]+M[3][3]*v[3];

(2)循環(huán)嵌套。把相關(guān)循環(huán)放到一個循環(huán)里,也會加快速度。

優(yōu)化前的代碼:

for(i=0;i<MAX;i++)/*initialize2darrayto0's*/

for(j=0;j<MAX;j++)

a[i][j]=0.0;

for(i=0;i<MAX;i++)/*put1'salongthediagonal*/

a[i][i]=1.0;

新代碼:

for(i=0;i<MAX;i++)/*initialize2darrayto0's*/

{

for(j=0;j<MAX;j++)

a[i][j]=0.0;

a[i][i]=1.0;/*put1'salongthediagonal*/

}

7.函數(shù)優(yōu)化

(1)不定義不使用的返回值。函數(shù)定義并不知道函數(shù)返回值是否被使用,假如返回值從來不會被用到,應(yīng)該使用void來明確聲明函數(shù)不返回任何值。

(2)減少函數(shù)調(diào)用參數(shù)。使用全局變量比用函數(shù)傳遞參數(shù)更加有效率。這樣做去除了函數(shù)調(diào)用參數(shù)入棧和函數(shù)完成后參數(shù)出棧所需要的時間。但是使用全局變量會影響程序的模塊化和重入,故要慎重使用。

(3)所有函數(shù)都應(yīng)該有原型定義。一般來說,所有函數(shù)都應(yīng)該有原型定義。原型定義可以傳達(dá)給編譯器更多的可能用于優(yōu)化的信息。通過代碼優(yōu)化,可以提高代碼的執(zhí)行效率,從而提升程序的品質(zhì)。因而優(yōu)化代碼是程序員提高自身水平、提高技能的一個很重要的途徑。不同的代碼有不同的分析方法,有不同的優(yōu)化方法,而這全憑程序員的經(jīng)驗(yàn)積累和自身水平。優(yōu)化是一門平衡的藝術(shù),它往往要以犧牲程序的可讀性或者增加代碼長度為代價。7.5.3網(wǎng)絡(luò)優(yōu)化

在現(xiàn)有的網(wǎng)絡(luò)狀態(tài)下,使用者經(jīng)常會遇到帶寬擁塞、應(yīng)用性能低下、蠕蟲病毒、DDoS肆虐、惡意入侵等對網(wǎng)絡(luò)使用及資源有負(fù)面影響的問題及困擾。網(wǎng)絡(luò)優(yōu)化功能是針對現(xiàn)有的防火墻、安防及入侵檢測、負(fù)載均衡、頻寬管理、網(wǎng)絡(luò)防毒等設(shè)備及網(wǎng)絡(luò)問題的補(bǔ)充,能夠通過接入硬件及軟件操作的方式進(jìn)行參數(shù)采集、數(shù)據(jù)分析,找出影響網(wǎng)絡(luò)質(zhì)量的原因,通過技術(shù)手段或增加相應(yīng)的硬件設(shè)備及調(diào)整使網(wǎng)絡(luò)達(dá)到最佳運(yùn)行狀態(tài)的方法。網(wǎng)絡(luò)優(yōu)化使網(wǎng)絡(luò)資源獲得最佳效益,同時了解網(wǎng)絡(luò)的增長趨勢并提供更好的解決方案。網(wǎng)絡(luò)優(yōu)化產(chǎn)品是實(shí)現(xiàn)網(wǎng)絡(luò)應(yīng)用性能加速,安全內(nèi)容管理,安全事件管理,用戶管理,網(wǎng)絡(luò)資源管理與優(yōu)化,桌面系統(tǒng)管理,流量模式監(jiān)控、測量、追蹤、分析和管理,提高在廣域網(wǎng)上應(yīng)用傳輸?shù)男阅艿墓δ苄援a(chǎn)品,主要包括網(wǎng)絡(luò)資源管理器、應(yīng)用性能加速器、網(wǎng)頁性能加速器三大類。應(yīng)針對不同的需求及功能要求進(jìn)行網(wǎng)絡(luò)優(yōu)化。 7.6代碼評審和版本控制

7.6.1代碼評審

代碼評審是項(xiàng)目開發(fā)過程中的重要環(huán)節(jié)。有效的代碼評審,可以在測試前靜態(tài)地發(fā)現(xiàn)bug。實(shí)踐證明,bug發(fā)現(xiàn)的時間越早,越利于bug的解決和降低解決成本。代碼評審能夠有效地督促編碼規(guī)范的實(shí)施,提高代碼的可讀性和可維護(hù)性。在代碼的評審過程中,項(xiàng)目組成員互相交流,取長補(bǔ)短,促進(jìn)項(xiàng)目組整體技能的提升??傊?,項(xiàng)目開發(fā)過程中的代碼評審和其他各項(xiàng)評審工作對提高項(xiàng)目產(chǎn)品質(zhì)量有重要貢獻(xiàn)。那么什么時候進(jìn)行代碼評審呢?代碼評審的粒度又該如何確定呢?一般是在代碼已具雛形,并且已通過單元測試,未提交進(jìn)行集成測試之前進(jìn)行代碼評審。評審的粒度要看代碼的規(guī)模,當(dāng)然評審的代碼覆蓋面越大,代碼的質(zhì)量越有保證。對于涉及業(yè)務(wù)流程較復(fù)雜的模塊,一定要和熟悉業(yè)務(wù)的人一起完成代碼的評審,對這類模塊應(yīng)給予重點(diǎn)關(guān)注,因?yàn)橥鶚I(yè)務(wù)流程邏輯的錯誤多于語言使用的錯誤。還有就是在系統(tǒng)第一版發(fā)布后,如果有需求變動,需要增加新功能,那么這時代碼評審的效果可能好于簡單的測試,當(dāng)然兩者都要有才能保證代碼質(zhì)量更高。代碼評審應(yīng)按照一定的流程作業(yè),這樣可以降低評審成本,提高評審效率。代碼評審流程介紹如下:

(1)代碼評審發(fā)起。代碼評審發(fā)起要由專人負(fù)責(zé),負(fù)責(zé)人要控制整個評審過程。負(fù)責(zé)人負(fù)責(zé)確定評審范圍、評審人、評審結(jié)果交付日期和組織召開評審會議。負(fù)責(zé)人還要編寫《代碼評審評審點(diǎn)列表》(CheckList),該表列舉出代碼評審過程重點(diǎn)檢查的項(xiàng)目,供評審人逐一檢查代碼。

(2)負(fù)責(zé)人發(fā)起代碼評審。負(fù)責(zé)人告知評審人代碼的評審范圍,確定被評審代碼的版本號,告知評審人評審結(jié)果的交付時間。負(fù)責(zé)人還應(yīng)該為評審人提供相關(guān)的資料,例如《編碼規(guī)約》等。

(3)評審人評審代碼。評審人按照負(fù)責(zé)人告知的評審范圍,認(rèn)真評審代碼,填寫評審報告,在規(guī)定的時間內(nèi)完成評審。填寫評審報告要明確描述問題發(fā)現(xiàn)點(diǎn)的位置,要寫清代碼文件的版本號和問題點(diǎn)的行號。

(4)負(fù)責(zé)人將評審結(jié)果轉(zhuǎn)交給代碼編寫人,編寫人認(rèn)真核對評審報告,修正代碼。編寫人要認(rèn)真填寫評審報告,要寫清修正后代碼文件的版本號和修正點(diǎn)的行號。

(5)召開評審會議。會上逐一對評審報告認(rèn)真分析,評審人和代碼編寫人要對每一項(xiàng)評審結(jié)果達(dá)成共識。

(6)負(fù)責(zé)人編寫評審總結(jié),將評審中總結(jié)出的問題和經(jīng)驗(yàn)通知項(xiàng)目組成員。7.6.2版本控制

在軟件開發(fā)中經(jīng)常出現(xiàn)一些與版本控制密切相關(guān)的典型問題,如:

(1)軟件代碼的一致性。軟件的開發(fā)、維護(hù)和升級,往往是多個人共同協(xié)作的過程。不同人對同一個軟件的不同部分同時做著修改,這種行為有時會出現(xiàn)彼此交叉的情況。由于同一軟件在各自開發(fā)人員的機(jī)器上都有拷貝,軟件的全部代碼都暴露在每個開發(fā)人員面前,原則上他有權(quán)限可以不加限制地更改軟件的任何部分。而當(dāng)他們修改的內(nèi)容屬于公共部分,或者需要被其他人員所負(fù)責(zé)的部分調(diào)用時(軟件各模塊間的彼此依賴關(guān)系決定了這種情況是經(jīng)常發(fā)生的),這種修改就屬于交叉情況。此時,就有可能出現(xiàn)代碼的不一致現(xiàn)象。比如:修改者在改動了某個公共函數(shù)的同時也修改了其調(diào)用接口,若其他人員沒有得知此事,而在各自機(jī)器上仍調(diào)用原來版本的函數(shù),則在整合時就會出現(xiàn)錯誤。另一種更為嚴(yán)重的情況是,修改者決定廢棄原有函數(shù)而另外編寫一個新的函數(shù),但他并未刪除原有函數(shù),這種情況即使在最后的整合中也可能不會被察覺,如果將這種一致性錯誤的糾正延遲到測試階段,則會增加調(diào)試的難度,從而降低開發(fā)效率。為了始終保證代碼的一致性,一種解決辦法是,要求修改者每次修改后都通過某種方式告知同組其他人員,或者隨時對軟件做整合。但是這樣一方面會增加開發(fā)人員的負(fù)擔(dān),另一方面也降低了軟件的開發(fā)效率。

(2)軟件內(nèi)容的冗余問題。軟件在各開發(fā)人員的機(jī)器上都有拷貝,并且同一個開發(fā)人員在不同時期也會在本機(jī)保留當(dāng)時的軟件版本,也就是說,一臺機(jī)器上還可能有不止一個版本的軟件。這類似于一種信息的冗余。對于不同版本而言,其差別有時可能并不很大。如果說不必要地占用存儲空間是一個次要問題的話,那么另一個問題可能更重要——隨著時間的推移,開發(fā)人員可能對自己機(jī)器上的不同版本間具體差異的了解變得模糊不清,甚至忘記了當(dāng)時區(qū)分這些版本的原因,這會給整合帶來麻煩。而且,如果需要同時維護(hù)多個版本,則對某個版本的改動可能需要反映到其余版本的對應(yīng)處,很難保證這一過程不會出差錯。還有一點(diǎn),作為

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論