第八章編碼和語言的選擇_第1頁
第八章編碼和語言的選擇_第2頁
第八章編碼和語言的選擇_第3頁
第八章編碼和語言的選擇_第4頁
第八章編碼和語言的選擇_第5頁
已閱讀5頁,還剩117頁未讀, 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

第八章編碼和語言的選擇

做為軟件工程過程的一個階段,程序編碼是設計的繼續(xù)。程序設計語言的特性和程序設計風格會深刻地影響軟件的質(zhì)量和可維護性。為了保證程序編碼的質(zhì)量,程序員必須深刻理解、熟練掌握并正確地運用程序設計語言的特性。此外,還要求源程序具有良好的結構性和良好的程序設計風格。教學內(nèi)容:§8.1編碼的目的§8.2編碼的風格

§8.3編碼使用的語言教學目的及要求:了解語言的選擇和程序設計風格會影響到軟件的質(zhì)量和可維護性§8.1編碼的目的使用選定的程序設計語言,把模塊的過程性描述翻譯為用該語言書寫的源程序?!?.2編碼的風格程序?qū)嶋H上也是一種供人閱讀的文章,有一個文章的風格問題。應該使程序具有良好的風格。從20世紀70年代以來,編碼的目標從強調(diào)效率轉(zhuǎn)變?yōu)閺娬{(diào)清晰。與此相應,編碼的風格從追求“聰明”和“技巧”,變?yōu)樘岢昂喢鳌焙汀爸苯印?。人們逐漸認識到,良好的編碼風格能在一定程度上彌補語言存在的缺點,反之,不注意風格,即使使用了結構化的現(xiàn)代語言,也很難寫出高質(zhì)量的程序。當多個程序員合作編寫一個大的程序時,尤其需要強調(diào)良好的和一致的風格,以利于相互通信,減少因不協(xié)調(diào)而引起的問題。1974年,Kernighan與Plauger在《TheElementsofProgranmmingStyle》中,把編碼風格歸結為7個問題,70余條指導原則,下面從控制結構、GOTO語句、代碼文檔化和輸入輸出等方面,簡述編碼風格的要求:使用標準的控制結構有限制地使用goto語句實現(xiàn)源程序的文檔化滿足運行工程學的輸入輸出風格程序設計風格

源程序文檔化

數(shù)據(jù)說明

輸入/輸出

效率

使用標準的控制結構

語句結構結構化程序設計主要包括兩方面:在編寫程序時,強調(diào)使用幾種基本控制結構,通過組合嵌套,形成程序的控制結構。盡可能避免使用GOTO語句。在程序設計過程中,盡量采用自頂向下和逐步細化的原則,由粗到細,一步步展開。使用標準的控制結構結構化程序設計的主要原則使用語言中的順序、選擇、重復等有限的基本控制結構表示程序邏輯。選用的控制結構只準許有一個入口和一個出口。程序語句組成容易識別的塊,每塊只有一個入口和一個出口。復雜結構應該用基本控制結構進行組合嵌套來實現(xiàn)。語言中沒有的控制結構,可用一段等價的程序段模擬,但要求該程序段在整個系統(tǒng)中應前后一致。嚴格控制GOTO語句,僅在下列情形才可使用:

①用一個非結構化的程序設計語言去實現(xiàn)一個結構化的構造。

②若不使用GOTO語句就會使程序功能模糊。

③在某種可以改善而不是損害程序可讀性的情況下。

例1打印A、B、C三數(shù)中最小者程序

程序1

if(A<B)

goto120;

if(B<C)goto110;

100write(C);

goto140;

110write(B);

goto140;

120if(A<C)goto130;

goto100;

130write(A);

140end

程序2

if(A<B)and(A<C)thenwrite(A)

else if(A

B)and(B<C)then

write(B)

else

write(C)endifendif例2用二分法求方程f(x)=0在區(qū)間[a..b]中的根的程序假設在閉區(qū)間[a..b]上函數(shù)f(x)有唯一的一個零點,eps是一個給定的很小的正數(shù),用于迭代收斂的判斷。

f0=f(a);f1=f(b); //程序1if(f0*f1<=0){

x0=a;x1=b;

for(i=1;i<=n;i++){

xm=(x0+x1)/2;fm=f(xm);

if(abs(fm)<eps||abs(x1-x0)<eps)gotofinish;

if(f0*fm>0){x0=xm;f0=fm;}

elsex1=xm;

}

finish:printf(“\nTherootofthisequationis%d\n”,xm);}

finish:printf(“\nTherootofthisequationis%d\n”,xm);}單入口,兩出口正常出口是循環(huán)達到n次,非正常出口是循環(huán)中途控制轉(zhuǎn)出到標號finish所在位置它不滿足結構化的要求

f0=f(a);f1=f(b);//程序2

if(f0*f1<=0){

x0=a;x1=b;

for(i=1;i<=n;i++){

xm=(x0+x1)/2;fm=f(xm);

if(abs(fm)<eps||abs(x1-x0)<eps)break;

if(f0*fm>0)

{x0=xm;f0=fm;}

else

x1=xm;

}}

該程序利用了C語言中的一個語句break,但仍然不是結構化的程序,它與程序段1完成的工作相同,由于將轉(zhuǎn)移語句與轉(zhuǎn)出條件的判斷聯(lián)系在一起,可讀性好。

f0=f(a);f1=f(b);//程序3if(f0*f1<=0){

x0=a;x1=b;i=1;finished=0;

while(i<=n&&finished==0){

xm=(x0+x1)/2;fm=f(xm);

if(abs(fm)<eps||abs(x1-x0)<eps)finished=1;

if(finished==0)

if(f0*fm>0)

{x0=xm;f0=fm;}

else

x1=xm

}}

if(f0*fm>0)

{x0=xm;f0=fm;}

else

x1=xm

;

}}

引入布爾變量

finished,改for

型循環(huán)為while

型,將單入口多出口結構改為單入口單出口結構。自頂向下,逐步求精在詳細設計和編碼階段,應當采取自頂向下,逐步求精的方法。把一個模塊的功能逐步分解,細化為一系列具體的步驟,進而翻譯成一系列用某種程序設計語言寫成的程序。例,用篩選法求100以內(nèi)的素數(shù)篩選法就是從2到100中去掉2,3,…,9,10的倍數(shù),剩下的就是100以內(nèi)的素數(shù)。為了解決這個問題,可先按程序功能寫出一個框架。main(){//程序框架

建立2到100的數(shù)組A[],其中A[i]=i;

-----------------------------------1

建立2到10的素數(shù)表B[],其中存放2

到10以內(nèi)的素數(shù);-----------2

若A[i]=i是B[]中任一數(shù)的倍數(shù),則剔除A[i];---------------------3

輸出A[]中所有沒有被剔除的數(shù);

-----------------------------------4}

main(){

/*建立2到100的數(shù)組A[],其中A[i]=i*/

for(i=2;i<=100;i++)A[i]=i;

/*建立2到10的素數(shù)表B[],其中存放2到

10以內(nèi)的素數(shù)*/

B[1]=2;B[2]=3;B[3]=5;B[4]=7;

/*若A[i]=i是B[]中任一數(shù)的倍數(shù),則剔除A[i]*/

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

檢查A[]所有的數(shù)能否被B[j]整除并將能被整除的數(shù)從A[]中剔除;

-----3.1

/*輸出A[]中所有沒有被剔除的數(shù)*/

for(i=2;i<=100;i++)

若A[i]沒有被剔除,則輸出之

---4.1}對框架中的局部再做細化,得到整個程序。main(){

/*建立2到100的數(shù)組A[],其中A[i]=i*/

for(i=2;i<=100;i++)A[i]=i;

/*建立2到10的素數(shù)表B[],其中存放2到

10以內(nèi)的素數(shù)*/

B[1]=2;B[2]=3;B[3]=5;B[4]=7;

/*若A[i]=i是B[]中任一數(shù)的倍數(shù),則剔除

A[i]*/

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

/*檢查A[]所有的數(shù)能否被B[j]整除并將能被整除的數(shù)從A[]中剔除*/

for(i=2;i<=100;i++)

if(A[i]/B[j]*B[j]==A[i])

A[i]=0;

/*輸出A[]中所有沒有被剔除的數(shù)*/

for(i=2;

i<=100;i++)

/*若A[i]沒有被剔除,則輸出之*/

if(A[i]!=0)

printf(“A[%d]=%d\n”,I,A[i]);

}自頂向下,逐步求精方法的優(yōu)點符合人們解決復雜問題的普遍規(guī)律??商岣哕浖_發(fā)的成功率和生產(chǎn)率用先全局后局部,先整體后細節(jié),先抽象后具體的逐步求精的過程開發(fā)出來的程序具有清晰的層次結構,程序容易閱讀和理解程序自頂向下,逐步細化,分解成一個樹形結構。在同一層的節(jié)點上的細化工作相互獨立。有利于編碼、測試和集成每一步工作僅在上層節(jié)點的基礎上做不多的設計擴展,便于檢查有利于設計的分工和組織工作。逐步細化程序的樹型結構

標識符的命名安排注釋程序的視覺組織

源程序文檔化標識符的命名符號名即標識符,包括模塊名、變量名、常量名、標號名、子程序名、數(shù)據(jù)區(qū)名以及緩沖區(qū)名等。這些名字應能反映它所代表的實際東西,應有一定實際意義。例如,表示次數(shù)的量用Times,表示總量的用Total,表示平均值的用Average,表示和的量用Sum等。名字不是越長越好,應當選擇精煉的意義明確的名字。必要時可使用縮寫名字,但這時要注意縮寫規(guī)則要一致,并且要給每一個名字加注釋。同時,在一個程序中,一個變量只應用于一種用途。例如,在一個程序中定義了一個變量temp,它在程序的前半段代表“Temperature”,在程序的后半段則代表“Temporary”,這使程序閱讀者不知多措。程序的注釋

夾在程序中的注釋是程序員與日后的程序讀者之間通信的重要手段。注釋決不是可有可無的。一些正規(guī)的程序文本中,注釋行的數(shù)量占到整個源程序的1/3到1/2,甚至更多。注釋分為序言性注釋和功能性注釋。序言性注釋通常置于每個程序模塊的開頭部分,它應當給出程序的整體說明,對于理解程序本身具有引導作用。有些軟件開發(fā)部門對序言性注釋做了明確而嚴格的規(guī)定,要求程序編制者逐項列出。有關項目包括:

程序標題;

有關本模塊功能和目的的說明;

主要算法;

接口說明:包括調(diào)用形式、參數(shù)描述、子程序清單;

有關數(shù)據(jù)描述:重要的變量及其用途、約束或限制條件,以及其它有關信息;

模塊位置:在哪一個源文件中,或隸屬于哪一個軟件包;

開發(fā)簡歷:模塊設計者、復審者、復審日期、修改日期及有關說明等。功能性注釋功能性注釋嵌在源程序體中,用以描述其后的語句或程序段是在做什么工作,或是執(zhí)行了下面的語句會怎么樣。而不要解釋下面怎么做。例如,

/*ADDAMOUNTTOTOTAL*/

TOTAL=AMOUNT+TOTAL

不好

如果注明把月銷售額計入年度總額,便使讀者理解了下面語句的意圖:

/*ADDMONTHLY-SALESTOANNUAL-TOTAL*/

TOTAL=AMOUNT+TOTAL要點描述一段程序,而不是每一個語句;用縮進和空行,使程序與注釋容易區(qū)別;注釋要正確。視覺組織空格、空行和移行恰當?shù)乩每崭瘢梢酝怀鲞\算的優(yōu)先性,避免發(fā)生運算的錯誤。例如,將表達式

(A<-17)ANDNOT(B<=49)ORC

寫成

(A<-17)ANDNOT(B<=49)ORC自然的程序段之間可用空行隔開;移行也叫做向右縮格。它是指程序中的各行不必都在左端對齊,都從第一格起排列。這樣做使程序完全分不清層次關系。對于選擇語句和循環(huán)語句,把其中的程序段語句向右做階梯式移行。使程序的邏輯結構更加清晰。例如:兩重選擇結構嵌套,寫成下面的移行形式,層次就清楚得多。

IF(…)

THEN

IF(…)

THEN

……

ELSE

……

ENDIF

……

ELSE

……

ENDIF在設計階段已經(jīng)確定了數(shù)據(jù)結構的組織及其復雜性。在編寫程序時,則需要注意數(shù)據(jù)說明的風格。為了使程序中數(shù)據(jù)說明更易于理解和維護,必須注意以下幾點。數(shù)據(jù)說明的次序應當規(guī)范化說明語句中變量安排有序化使用注釋說明復雜數(shù)據(jù)結構數(shù)據(jù)說明數(shù)據(jù)說明的次序應當規(guī)范化數(shù)據(jù)說明次序規(guī)范化,使數(shù)據(jù)屬性容易查找,也有利于測試,排錯和維護。原則上,數(shù)據(jù)說明的次序與語法無關,其次序是任意的。但出于閱讀、理解和維護的需要,最好使其規(guī)范化,使說明的先后次序固定。

例如,在FORTRAN程序中數(shù)據(jù)說明次序 ①常量說明 ②簡單變量類型說明 ③數(shù)組說明 ④公用數(shù)據(jù)塊說明 ⑤所有的文件說明在類型說明中還可進一步要求。例如,可按如下順序排列: ①整型量說明 ②實型量說明 ③字符量說明 ④邏輯量說明說明語句中變量安排有序化當多個變量名在一個說明語句中說明時,應當對這些變量按字母的順序排列。帶標號的全程數(shù)據(jù)(如FORTRAN的公用塊)也應當按字母的順序排列。例如,把

integersize,length,width,cost,price

寫成

integer

cost,length,price,size,width

使用注釋說明復雜數(shù)據(jù)結構如果設計了一個復雜的數(shù)據(jù)結構,應當使用注釋來說明在程序?qū)崿F(xiàn)時這個數(shù)據(jù)結構的固有特點。例如,對PL/1的鏈表結構和Pascal中用戶自定義的數(shù)據(jù)類型,都應當在注釋中做必要的補充說明。語句結構在設計階段確定了軟件的邏輯流結構,但構造單個語句則是編碼階段的任務。語句構造力求簡單、直接,不能為了片面追求效率而使語句復雜化。在一行內(nèi)只寫一條語句在一行內(nèi)只寫一條語句,并且采取適當?shù)囊菩懈袷?,使程序的邏輯和功能變得更加明確。許多程序設計語言允許在一行內(nèi)寫多個語句。但這種方式會使程序可讀性變差。因而不可取。

例如,有一段排序程序

FORI:=1TON-1DOBEGINT:=I;FORJ:=I+1TONDOIFA[J]<A[T]THENT:=J;IFT≠ITHENBEGINWORK:=A[T];A[T]:=A[I];A[I]:=WORK;ENDEND;由于一行中包括了多個語句,掩蓋了程序的循環(huán)結構和條件結構,使其可讀性變得很差。FORI:=1TON-1DO//改進布局

BEGIN

T:=I;

FORJ:=I+1TONDO

IFA[J]<A[T]THENT:=J;

IFT≠ITHEN

BEGIN

WORK:=A[T];

A[T]:=A[I];

A[I]:=WORK;

END

END;程序編寫首先應當考慮清晰性程序編寫首先應當考慮清晰性,不要刻意追求技巧性,使程序編寫得過于緊湊。例如,有一個用C語句寫出的程序段:

A[I]=A[I]+A[T];

A[T]=A[I]-A[T];

A[I]=A[I]-A[T];

此段程序可能不易看懂,有時還需用實際數(shù)據(jù)試驗一下。實際上,這段程序的功能就是交換A[I]和A[T]中的內(nèi)容。目的是為了節(jié)省一個工作單元。如果改一下:

WORK=A[T];

A[T]=A[I];

A[I]=WORK;

就能讓讀者一目了然了。程序要能直截了當?shù)卣f明程序員的用意程序編寫得要簡單,寫清楚,直截了當?shù)卣f明程序員的用意。例如:

for(i=1;i<=n;i++)

for(j=1;j<=n;j++)

V[i][j]=(i/j)*(j/i)

除法運算(/)在除數(shù)和被除數(shù)都是整型量時,其結果只取整數(shù)部分,而得到整型量。

當i<j

時,i/j=0

當j<i

時,j/i=0

得到的數(shù)組當i≠j時

V[i][j]=(i/j)*(j/i)=0

當i=j時

V[i][j]=(i/j)*(j/i)=1這樣得到的結果V

是一個單位矩陣。寫成以下的形式,就能讓讀者直接了解程序編寫者的意圖。

for(i=1;i<=n;i++)

for(j=1;j<=n;j++)

if(i==j)

V[i][j]=1.0;

ELSE

V[i][j]=0.0;

除非對效率有特殊的要求,程序編寫要做到清晰第一,效率第二。不要為了追求效率而喪失了清晰性。事實上,程序效率的提高主要應通過選擇高效的算法來實現(xiàn)。首先要保證程序正確,然后才要求提高速度。反過來說,在使程序高速運行時,首先要保證它是正確的。

避免使用臨時變量而使可讀性下降。例如,有的程序員為了追求效率,往往喜歡把表達式

A[I]+1/A[I];

寫成AI=A[I];X=AI+1/AI;

這樣將一句分成兩句寫,會產(chǎn)生意想不到的問題。

讓編譯程序做簡單的優(yōu)化。盡可能使用庫函數(shù)避免不必要的轉(zhuǎn)移。同時如果能保持程序可讀性,則不必用GOTO語句。例如,有一個求三個數(shù)中最小值的程序:

IF(X<Y)GOTO30

IF(Y<Z)GOTO50

SMALL=ZGOTO7030IF(X<Z)GOTO60

SMALL=ZGOTO7050SMALL=YGOTO7060SMALL=X70CONTINUE

程序只需編寫成:

small=x;

if(y<small)small=y(tǒng);

if(z<small)small=z;

所以程序應當簡單,不必過于深奧,避免使用GOTO語句繞來繞去。盡量只采用三種基本的控制結構來編寫程序。除順序結構外,使用

if-then-else來實現(xiàn)選擇結構;使用

do-until或do-while來實現(xiàn)循環(huán)結構。

避免使用空的ELSE語句和IF…THENIF…的語句。這種結構容易使讀者產(chǎn)生誤解。例如,

if(char>='a’)

if(char<=’z’)

cout<<“Thisisaletter?!?

else

cout<<“Thisisnotaletter?!?

可能產(chǎn)生二義性問題。避免采用過于復雜的條件測試。盡量減少使用“否定”條件的條件語句。例如,如果在程序中出現(xiàn)

if(!(char<‘0’||char>‘9’))……

改成

if(char>='0’&&char<='9’)……

不要讓讀者繞彎子想。盡可能用通俗易懂的偽碼來描述程序的流程,然后再翻譯成必須使用的語言。數(shù)據(jù)結構要有利于程序的簡化。要模塊化,使模塊功能盡可能單一化,模塊間的耦合能夠清晰可見。利用信息隱蔽,確保每一個模塊的獨立性。從數(shù)據(jù)出發(fā)去構造程序。不要修補不好的程序,要重新編寫。也不要一味地追求代碼的復用,要重新組織。對太大的程序,要分塊編寫、測試,然后再集成。對遞歸定義的數(shù)據(jù)結構盡量使用遞歸過程。輸入和輸出信息是與用戶的使用直接相關的。輸入和輸出的方式和格式應當盡可能方便用戶的使用。一定要避免因設計不當給用戶帶來的麻煩。因此,在軟件需求分析階段和設計階段,就應基本確定輸入和輸出的風格。系統(tǒng)能否被用戶接受,有時就取決于輸入和輸出的風格。

輸入/輸出不論是批處理的輸入/輸出方式,還是交互式的輸入/輸出方式,在設計和編碼時都應考慮下列原則:對所有的輸入數(shù)據(jù)都要進行檢驗,識別錯誤的輸入,以保證每個數(shù)據(jù)的有效性;檢查輸入項的各種重要組合的合理性,必要時報告輸入狀態(tài)信息;使得輸入的步驟和操作盡可能簡單,并保持簡單的輸入格式;輸入數(shù)據(jù)時,應允許使用自由格式輸入;應允許缺省值;輸入一批數(shù)據(jù)時,最好使用輸入結束標志,而不要由用戶指定輸入數(shù)據(jù)數(shù)目;在交互式輸入輸入時,要在屏幕上使用提示符明確提示交互輸入的請求,指明可使用選擇項的種類和取值范圍。同時,在數(shù)據(jù)輸入的過程中和輸入結束時,也要在屏幕上給出狀態(tài)信息;當程序設計語言對輸入/輸出格式有嚴格要求時,應保持輸入格式與輸入語句的要求的一致性;給所有的輸出加注解,并設計輸出報表格式。

輸入/輸出風格還受到許多其它因素的影響。如輸入/輸出設備(例如終端的類型、圖形設備、數(shù)字化轉(zhuǎn)換設備等)、用戶的熟練程度、以及通信環(huán)境等。

討論效率的準則

程序的效率是指程序的執(zhí)行速度及程序所需占用的內(nèi)存的存儲空間。程序編碼是最后提高運行速度和節(jié)省存儲的機會,因此在此階段不能不考慮程序的效率。讓我們首先明確討論程序效率的幾條準則

效率

效率是一個性能要求,應當在需求分析階段給出。軟件效率以需求為準,不應以人力所及為準。好的設計可以提高效率。程序的效率與程序的簡單性相關。一般說來,任何對效率無重要改善,且對程序的簡單性、可讀性和正確性不利的程序設計方法都是不可取的。算法對效率的影響源程序的效率與詳細設計階段確定的算法的效率直接有關。在詳細設計翻譯轉(zhuǎn)換成源程序代碼后,算法效率反映為程序的執(zhí)行速度和存儲容量的要求。設計向程序轉(zhuǎn)換過程中的指導原則:

在編程序前,盡可能化簡有關的算術表達式和邏輯表達式;

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

③盡量避免使用多維數(shù)組;

④盡量避免使用指針和復雜的表;

⑤采用“快速”的算術運算;

不要混淆數(shù)據(jù)類型,避免在表達式中出現(xiàn)類型混雜;⑦盡量采用整數(shù)算術表達式和布爾表達式;⑧選用等效的高效率算法;許多編譯程序具有“優(yōu)化”功能,可以自動生成高效率的目標代碼。影響存儲器效率的因素在大中型計算機系統(tǒng)中,存儲限制不再是主要問題。在這種環(huán)境下,對內(nèi)存采取基于操作系統(tǒng)的分頁功能的虛擬存儲管理。存儲效率與操作系統(tǒng)的分頁功能直接有關。采用結構化程序設計,將程序功能合理分塊,使每個模塊或一組密切相關模塊的程序體積大小與每頁的容量相匹配,可減少頁面調(diào)度,減少內(nèi)外存交換,提高存儲效率。

在微型計算機系統(tǒng)中,存儲器的容量對軟件設計和編碼的制約很大。因此要選擇可生成較短目標代碼且存儲壓縮性能優(yōu)良的編譯程序,有時需采用匯編程序。提高存儲器效率的關鍵是程序的簡單性。影響輸入/輸出的因素輸入/輸出可分為兩種類型:面向人(操作員)的輸入/輸出面向設備的輸入/輸出如果操作員能夠十分方便、簡單地錄入輸入數(shù)據(jù),或者能夠十分直觀、一目了然地了解輸出信息,則可以說面向人的輸入/輸出是高效的。

關于面向設備的輸入/輸出,可以提出一些提高輸入/輸出效率的指導原則:輸入/輸出的請求應當最小化;對于所有的輸入/輸出操作,安排適當?shù)木彌_區(qū),以減少頻繁的信息交換。對輔助存儲(例如磁盤),選擇盡可能簡單的,可接受的存取方法;

對輔助存儲的輸入/輸出,應當成塊傳送;

對終端或打印機的輸入/輸出,應考慮設備特性,盡可能改善輸入/輸出的質(zhì)量和速度;任何不易理解的,對改善輸入/輸出效果關系不大的措施都是不可取的;任何不易理解的所謂“超高效”的輸入/輸出是毫無價值的;

程序復雜性度量程序復雜性主要指模塊內(nèi)程序的復雜性。它直接關聯(lián)到軟件開發(fā)費用的多少,開發(fā)周期的長短和軟件內(nèi)部潛伏錯誤的多少。減少程序復雜性,可提高軟件的簡單性和可理解性,并使軟件開發(fā)費用減少,開發(fā)周期縮短,軟件內(nèi)部潛藏錯誤減少。復雜性度量需要滿足的假設為了度量程序復雜性,要求:它可以用來計算任何一個程序的復雜性;對于不合理的程序,例如對于長度動態(tài)增長的程序,或者對于原則上無法排錯的程序,不應當使用它進行復雜性計算;如果程序中指令條數(shù)、附加存儲量、計算時間增多,不會減少程序的復雜性。

代碼行度量法源代碼行數(shù)度量法基于兩個前提:

程序復雜性隨著程序規(guī)模的增加不均衡地增長;控制程序規(guī)模的方法最好是采用分而治之的辦法。將一個大程序分解成若干個簡單的可理解的程序段。方法的基本考慮是統(tǒng)計一個程序模塊的源代碼行數(shù)目,并以源代碼行數(shù)做為程序復雜性的度量。設每行代碼的出錯率為每100行源程序中可能有的錯誤數(shù)目。Thayer曾指出,程序出錯率的估算范圍是從0.04%~7%之間,即每100行源程序中可能存在0.04~7個錯誤。他還指出,每行代碼的出錯率與源程序行數(shù)之間不存在簡單的線性關系。

Lipow指出,對于小程序,每行代碼出錯率為1.3%~1.8%;對于大程序,每行代碼的出錯率增加到2.7%~3.2%之間,這只是考慮了程序的可執(zhí)行部分,沒有包括程序中的說明部分。Lipow及其他研究者得出一個結論:對于少于100個語句的小程序,源代碼行數(shù)與出錯率是線性相關的。隨著程序的增大,出錯率以非線性方式增長。McCabe度量法McCabe度量法,又稱環(huán)路復雜性度量,是一種基于程序控制流的復雜性度量方法。它基于一個程序模塊的程序圖中環(huán)路的個數(shù),因此計算它先要畫出程序圖。程序圖是退化的程序流程圖。流程圖中每個處理都退化成一個結點,流線變成連接不同結點的有向弧。程序圖僅描述程序內(nèi)部的控制流程,完全不表現(xiàn)對數(shù)據(jù)的具體操作,以及分支和循環(huán)的具體條件。計算環(huán)路復雜性的方法:根據(jù)圖論,在一個強連通的有向圖G中,環(huán)的個數(shù)由以下公式給出:

V(G)=m-n+p

其中,V(G)是有向圖G中環(huán)路個數(shù),m是圖G中弧數(shù),n是圖G中結點數(shù),p是圖G中的強連通分量個數(shù)。Myers建議,對于復合判定,例如,(A=0)∩(C=D)∪(X=‘A’)算做三個判定。為使圖成為強連通圖,從圖的入口點到出口點加一條用虛線表示的有向邊,使圖成為強連通圖。這樣就可以使用上式計算環(huán)路復雜性。在例示中,結點數(shù)n=11,弧數(shù)m=13,p=1,則有

V(G)=m-n+p=13-11+1=3.等于程序圖中弧所封閉的區(qū)域數(shù)。幾點說明環(huán)路復雜度取決于程序控制結構的復雜度。當程序的分支數(shù)目或循環(huán)數(shù)目增加時其復雜度也增加。環(huán)路復雜度與程序中覆蓋的路徑條數(shù)有關。環(huán)路復雜度是可加的。例如,模塊A的復雜度為3,模塊B的復雜度為4,則模塊A與模塊B的復雜度是7。

McCabe建議,對于復雜度超過10的程序,應分成幾個小程序,以減少程序中的錯誤。Walsh用實例證實了這個建議的正確性。在McCabe復雜度為10的附近,存在出錯率的間斷躍變。McCabe環(huán)路復雜度隱含的前提是:錯誤與程序的判定加上例行子程序的調(diào)用數(shù)目成正比。加工復雜性、數(shù)據(jù)結構、錄入與打亂輸入卡片的錯誤可以忽略不計。這種度量的缺點是:對于不同種類的控制流的復雜性不能區(qū)分

簡單IF語句與循環(huán)語句的復雜性同等看待

嵌套IF語句與簡單CASE語句的復雜性是一樣的

模塊間接口當成一個簡單分支一樣處理一個具有1000行的順序程序與一行語句的復雜性相同Halstead的軟件科學Halstead軟件科學研究確定計算機軟件開發(fā)中的一些定量規(guī)律,它采用以下一組基本的度量值。這些度量值通常在程序產(chǎn)生之后得出,或者在設計完成之后估算出。程序長度(預測的Halstead長度)

令n1表示程序中不同運算符(包括保留字)的個數(shù),令n2表示程序中不同運算對象的個數(shù),令H表示“程序長度”,則有

H=n1

log2n1+n2

log2n2這里,H是程序長度的預測值,它不等于程序中語句個數(shù)。

在定義中,運算符包括:算術運算符賦值符(=或:=)

邏輯運算符分界符(,或;或:)

關系運算符括號運算符子程序調(diào)用符數(shù)組操作符循環(huán)操作符等。特別地,成對的運算符,例如

“begin…end”、“for…to”、“repeat…until”、“while…do”、“if…then…else”、“(…)”等都當做單一運算符。

運算對象包括變量名和常數(shù)。實際的Halstead長度

設N1為程序中實際出現(xiàn)的運算符總個數(shù),N2為程序中實際出現(xiàn)的運算對象總個數(shù),N為實際的Halstead長度,則有

N=N1+N2

程序的詞匯表

Halstead定義程序的詞匯表為不同的運算符種類數(shù)n1和不同的運算對象種類數(shù)n2的總和。若令n為程序的詞匯表,則有

n=n1+n2

例如,用FORTRAN語言寫出的交換排序的例子

SUBROUTINESORT(X,N)

DIMENSIONX(N)

IF(N.LT.2)RETURN

DO20I=2,N

DO10J=1,I

IF(X(I).GE.X(J))GOTO10

SAVE=X(I)

X(I)=X(J)

X(J)=SAVE

10CONTINUE

20CONTINUE

RETURN

END

程序量程序量V可用下式得到

V=N

log2n

它表明了程序在詞匯上的復雜性。其最小值為

V*=(2+n2*)

log2(2+n2*)V

這里,2表明程序中至少有兩個運算符:賦值符=

和函數(shù)調(diào)用符

f()

,n2*表示輸入/輸出變量個數(shù)。

對于上面的例子,利用n1,N1,n2,N2,可以計算得

H=10

log210+7

log27=52.87N=28+22=50V=(28+22)

log2(10+7)=204等效的匯編語言程序的V=328。這說明匯編語言比FORTRAN語言需要更多的信息量(以bit表示)。

程序量比率(語言的抽象級別)

L=V*/V

或L=(2/n1)(n2/N2)

它表明了一個程序的最緊湊形式的程序量與實際程序量之比,反映了程序的效率。其倒數(shù)

D=1/L

表明了實現(xiàn)算法的困難程度。

程序員工作量

E=V/L

程序的潛在錯誤

Halstead度量可以用來預測程序中的錯誤。預測公式為

B=(N1+N2)log2(n1+n2)/3000

B為該程序的錯誤數(shù)。它表明程序中可能存在的差錯B應與程序量V成正比。

例如,一個程序?qū)?5個數(shù)據(jù)庫項共訪問1300次,對150個運算符共使用了1200次,那么預測該程序的錯誤數(shù):

B=(1200+1300)log2(75+150)/30006.5

即預測該程序中可能包含6~7個錯誤Halstead的重要結論程序的實際Halstead長度N可以由詞匯表n算出。即使程序還未編制完成,也能預先算出程序的實際Halstead長度N,雖然它沒有明確指出程序中到底有多少個語句。

這個結論非常有用。經(jīng)過多次驗證,預測的Halstead長度與實際的Halstead長度是非常接近的。

Halstead度量的缺點沒有區(qū)別自己編的程序與別人編的程序。這是與實際經(jīng)驗相違背的。這時應將外部調(diào)用乘上一個大于1的的常數(shù)Kf(應在1~5之間,它與文檔資料的清晰度有關)。沒有考慮非執(zhí)行語句。補救辦法:在統(tǒng)計n1、n2、N1、N2時,可以把非執(zhí)行語句中出現(xiàn)的運算對象,運算符統(tǒng)計在內(nèi)。在允許混合運算的語言中,每種運算符與它的運算對象相關。如果一種語言有整型、實型、雙精度型三種不同類型的運算對象,則任何一種基本算術運算符(+、-、×、/)實際上代表了=6種運算符。在計算時應考慮這種因數(shù)據(jù)類型而引起差異的情況。

沒有注意調(diào)用的深度。Halstead公式應當對調(diào)用子程序的不同深度區(qū)別對待。在計算嵌套調(diào)用的運算符和運算對象時,應乘上一個調(diào)用深度因子。這樣可以增大嵌套調(diào)用時的錯誤預測率。沒有把不同類型的運算對象,運算符與不同的錯誤發(fā)生率聯(lián)系起來,而是把它們同等看待。例如,對簡單if語句與

溫馨提示

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

評論

0/150

提交評論