編寫(xiě)優(yōu)質(zhì)無(wú)錯(cuò)代碼_第1頁(yè)
編寫(xiě)優(yōu)質(zhì)無(wú)錯(cuò)代碼_第2頁(yè)
編寫(xiě)優(yōu)質(zhì)無(wú)錯(cuò)代碼_第3頁(yè)
編寫(xiě)優(yōu)質(zhì)無(wú)錯(cuò)代碼_第4頁(yè)
編寫(xiě)優(yōu)質(zhì)無(wú)錯(cuò)代碼_第5頁(yè)
已閱讀5頁(yè),還剩9頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡(jiǎn)介

1、編寫(xiě)優(yōu)質(zhì)無(wú)錯(cuò)代碼http:/LinuxA 01-08-19 21:59 500p ariesram-      一. 引言          八月上旬,深圳舉辦了一個(gè)討論會(huì),主題是"編寫(xiě)優(yōu)質(zhì)無(wú)錯(cuò)代碼"。這個(gè)討論會(huì)吸引了深圳各大軟件公司,通信公司的程序員,系統(tǒng)分析員參加,并在討論會(huì)后紛紛表示,這種討論會(huì)很有實(shí)際價(jià)值,希望將這種形式的討論會(huì)繼續(xù)下去,形成一個(gè)論壇,以提高大家的編程水平和交換有價(jià)值的信息資料。   

2、;       這個(gè)活動(dòng)的發(fā)起是從網(wǎng)絡(luò)上開(kāi)始的。我偶然看到了這個(gè)討論會(huì)的論題,發(fā)生了興趣。本來(lái)周末的我一般是很懶的,沒(méi)什么事情是不會(huì)出門(mén)的。而當(dāng)我看到這論題后,就給舉辦者發(fā)信表示愿意參加。于是,一個(gè)周六的下午,我就坐在了討論會(huì)的現(xiàn)場(chǎng)。參加完這個(gè)討論后,我覺(jué)得有必要把其中的精華部分寫(xiě)下來(lái),和網(wǎng)絡(luò)上的廣大程序員共享,于是就有了這篇文章。      二.主題:      編寫(xiě)優(yōu)質(zhì)無(wú)錯(cuò)的代碼-討論會(huì)主題。   &#

3、160;  相信每個(gè)程序員都有這種希望,誰(shuí)都不愿意自己寫(xiě)出來(lái)的代碼在release之后出錯(cuò),需要不停的修改維護(hù)。但是,主持人提出了這樣一個(gè)問(wèn)題:"編寫(xiě)優(yōu)質(zhì)無(wú)錯(cuò)代碼是否必要?" 為什么呢?我稍微解釋一下。在項(xiàng)目的時(shí)間很      緊張的時(shí)候,是按期完成任務(wù)重要,還是代碼的穩(wěn)定性,優(yōu)質(zhì)無(wú)錯(cuò)重要呢?      主持人提出的四個(gè)具體問(wèn)題是:      1、編寫(xiě)優(yōu)質(zhì)無(wú)錯(cuò)的代碼的代價(jià)是什么?   &

4、#160;  2、代碼的質(zhì)量重要還是編寫(xiě)效率重要?      3、在壓力的情況下,你會(huì)犧牲質(zhì)量來(lái)提高效率么?      4、編寫(xiě)優(yōu)質(zhì)無(wú)錯(cuò)的代碼是否意味著效率的降低?          對(duì)于第一個(gè)問(wèn)題,編寫(xiě)優(yōu)質(zhì)無(wú)錯(cuò)代碼的代價(jià)當(dāng)然是時(shí)間,不過(guò)隨著編程人員的經(jīng)驗(yàn)逐漸豐富,所需要的時(shí)間也逐漸減少。對(duì)于第二個(gè)問(wèn)題,代碼的質(zhì)量比編寫(xiě)效率重要。當(dāng)你花了1周時(shí)間寫(xiě)出來(lái)的代碼需要你花一個(gè)月或者更長(zhǎng)的時(shí)間去debug

5、, 去修改錯(cuò)誤,這種效率的損失是得不償失的。對(duì)于第三個(gè)問(wèn)題, 這需要看項(xiàng)目經(jīng)理或者產(chǎn)品經(jīng)理的態(tài)度和專業(yè)精神了。如果在一個(gè)專業(yè)的項(xiàng)目經(jīng)理或者產(chǎn)品經(jīng)理的指揮下,當(dāng)然是首先保證質(zhì)量其次提高效率。而對(duì)于某些項(xiàng)目經(jīng)理或者產(chǎn)品經(jīng)理來(lái)說(shuō),按時(shí)完成任務(wù)是最重要的,他們往往不在乎在軟件發(fā)布之后花比開(kāi)發(fā)時(shí)間長(zhǎng)得多的時(shí)間去修改程序,維護(hù)錯(cuò)誤。因?yàn)?,?duì)于他們來(lái)說(shuō),首先是要完成任務(wù),好給上級(jí)領(lǐng)導(dǎo)交差,至于后期維護(hù),就是另外一個(gè)任務(wù)了,維護(hù)花的時(shí)間多,正說(shuō)明了他這個(gè)項(xiàng)目的復(fù)雜性和難度。而對(duì)于開(kāi)發(fā)人員來(lái)講,所希望的則正好相反。開(kāi)發(fā)人員不喜歡花太多的時(shí)間在一個(gè)爛攤子上。所以,在討論會(huì)上,大家紛紛表  &#

6、160;   示,應(yīng)該讓項(xiàng)目經(jīng)理或者產(chǎn)品經(jīng)理也來(lái)聽(tīng)一聽(tīng)這個(gè)討論會(huì):-)。      對(duì)于第四個(gè)問(wèn)題,當(dāng)然優(yōu)質(zhì)無(wú)錯(cuò)代碼不是意味著效率的降低,而是正好相反,對(duì)提高效率有很好的促進(jìn)作用。一個(gè)版本發(fā)布之后,如果因?yàn)殄e(cuò)誤太多,開(kāi)發(fā)人員不得不去花很多時(shí)間修改bug, 甚至要從系統(tǒng)的體系結(jié)構(gòu)方面去做      大的改動(dòng),重新編寫(xiě)部分代碼,這種效率的降低才是更大,更不能承受的。而且,花了太多的時(shí)間在老版本的維護(hù)上,必然影響到新版本的工程進(jìn)度,直接影響到整個(gè)產(chǎn)品線的質(zhì)量和進(jìn)度,嚴(yán)重的甚至?xí)У?/p>

7、整個(gè)產(chǎn)品。      對(duì)于這一個(gè)主題,我的回答是,在時(shí)間允許的范圍之內(nèi),盡量提高代碼的質(zhì)量,不追求慢工出細(xì)活,不追求代碼的100%無(wú)錯(cuò),但是要保證99%以上的無(wú)錯(cuò)。這樣,在時(shí)間的壓力下,在質(zhì)量要求的束縛下,就要求程序員有一個(gè)良      好的習(xí)慣,和穩(wěn)健的編程風(fēng)格,以保證代碼的優(yōu)質(zhì)無(wú)錯(cuò)。這就是第二個(gè)問(wèn)題:什么是編寫(xiě)優(yōu)質(zhì)無(wú)錯(cuò)的代碼的核心思想??jī)?yōu)質(zhì)無(wú)錯(cuò)是相對(duì)的,而不是絕對(duì)的。任何代碼,都不可能說(shuō)是絕對(duì)無(wú)錯(cuò)的,但是在絕大部分情況下,是穩(wěn)定的,強(qiáng)健的,優(yōu)質(zhì)的,無(wú)錯(cuò)的。每次發(fā)布的時(shí)候,都會(huì)對(duì)上次的發(fā)布版本

8、做若干修改,增強(qiáng)功能的同時(shí),也要修改若干bug。那么,核心思想就是:怎樣才能自動(dòng)地查出這個(gè)錯(cuò)誤。怎樣才能避免這個(gè)錯(cuò)誤。      三.編寫(xiě)優(yōu)質(zhì)無(wú)錯(cuò)代碼的經(jīng)驗(yàn)      在說(shuō)了上面很多理論性的問(wèn)題之后,來(lái)看一看具體問(wèn)題。先來(lái)看一看一個(gè)具體的題目:(我本人就是先在網(wǎng)上看了這個(gè)題目,才對(duì)這個(gè)討論會(huì)發(fā)生興趣的)      題目1:      作為開(kāi)發(fā)團(tuán)隊(duì)的一員,你需要實(shí)現(xiàn)一些庫(kù)函數(shù)提供給其他人使用。假設(shè)你

9、實(shí)現(xiàn)的一個(gè)函數(shù)原型如下:      int DoSomeThing(char* pParam)            .            你們約定好參數(shù)pParam不能為NULL,但為了防止調(diào)用者錯(cuò)誤傳遞NULL,你需要在你的函數(shù)里做判斷處理。      請(qǐng)問(wèn)你會(huì)選擇那種方式,并說(shuō)明原因?&#

10、160;     (a) if (!pParam)      return 0;      (b) if (!pParam)      return ERROR_PARAM;      (c) if (!pParam)      pParam = ""   &

11、#160;  .      (d) if (!pParam)      throw EXCEPTION_ERROR_PARAM;      (e) if (!pParam)      MessageBox(.);      (f) assert(!pParam);      (附加說(shuō)明一點(diǎn)

12、,基于目前開(kāi)發(fā)人員技術(shù)分布情況和參與討論會(huì)的人員的技術(shù)分布情況,這次所列舉的例子都是C/C+和Java方面的,不涉及到VB, PB, Delphi等語(yǔ)言。不過(guò)對(duì)于這些程序員,討論也是有借鑒作用的。)關(guān)于這個(gè)問(wèn)題,大概是所有的程序員都會(huì)遇到的。所以,在網(wǎng)上和討論會(huì)上,都發(fā)生了激烈的爭(zhēng)論和意見(jiàn)交換。我大概把主要的幾種觀點(diǎn)記錄了一下,列舉在下面:      1、選擇f的理由      因?yàn)榉荖ULL是約定,所以可以確定是調(diào)用者的問(wèn)題,f可以明確地指出這一點(diǎn),防止錯(cuò)誤擴(kuò)散。  

13、60;   我的附加說(shuō)明: 防止錯(cuò)誤擴(kuò)散的意思是,如果用其他方式,比如throwexception的方式,這個(gè)異常不一定會(huì)在調(diào)用此函數(shù)的上一層被捕捉到,可能會(huì)被繼續(xù)拋出直到最上一層或者直到在某一層被catch到,這樣的話,錯(cuò)誤就會(huì)距離發(fā)生地點(diǎn)很遠(yuǎn),擴(kuò)散開(kāi)來(lái)。這一觀點(diǎn),代表了一大部分的程序員的觀點(diǎn)。      2、反對(duì)用f      不贊成assert, assert更重要的作用是程序體里面的一個(gè)注釋, 在閱讀程序的時(shí)候起作用不能依賴他來(lái)檢測(cè)錯(cuò)誤, 很大程度上assert容易使

14、使用者依賴它本不應(yīng)該依賴的東西。      這也代表了部分程序員的觀點(diǎn),認(rèn)為assert是不可依賴的,而應(yīng)該依賴于錯(cuò)誤檢測(cè),比如返回值或者異常。      3、另外一種觀點(diǎn)      f和d都可取。如果沒(méi)有系統(tǒng)開(kāi)銷(xiāo)的考慮,d則更好些。可以一舉兩得。如果沒(méi)人catch這個(gè)exception,其結(jié)果就跟f一樣,按bug處理,dump core留下一stack trace。如果有人catch,那就按運(yùn)行錯(cuò)誤處理.但是返回一特初值表示錯(cuò)誤,只是將錯(cuò)誤上交

15、,掩耳盜鈴而已。最終總得有個(gè)人assert,messagebox,throwexception,perror+exit,或別得什么的。既然已經(jīng)是約定,就干脆付起責(zé)任。      4、一種反對(duì)d的理由      不可用d, 這就像你用人,卻不相信人一樣,偏要try,catch防范他。其實(shí)那個(gè)錯(cuò)是自己造成的,如果看到異常就容易不檢討自己。      5、關(guān)于觀點(diǎn)3的支持意見(jiàn)      討論過(guò)程中,有人

16、認(rèn)為assert檢查的是bug, 而異常是可以恢復(fù)的意外情況。所以,觀點(diǎn)3的支持者說(shuō):可恢復(fù)的意外是可以理解的,但可恢復(fù)的bug就沒(méi)什么意義了。既然已經(jīng)約定好了,你再違背,就屬于是bug而不是意外了(比如打不開(kāi)文件什么的)。很多庫(kù)函數(shù)都不檢查指針的合法性(除了系統(tǒng)調(diào)用以外,因?yàn)榭偛荒茏屜到y(tǒng)dump core吧),也不檢查指針是否為NULL(因?yàn)槿绻麑訉佣紮z查,必定勞民傷財(cái),干脆讓最上面調(diào)用的人在調(diào)用之外查)。      6、選擇d+f      選f+d, 好處如下:  &#

17、160;   a以最激烈的方式,充分暴露調(diào)用都的錯(cuò)誤!能及時(shí)修改BUG      b便于調(diào)試,問(wèn)題出現(xiàn)后,直接到事故現(xiàn)場(chǎng)。比120還快!      c對(duì)于realse版的代碼沒(méi)有任何副作用。      d以處理的代價(jià)來(lái)看 采用斷言也是編寫(xiě)最小一種。      e它是多語(yǔ)種,多平臺(tái)所通用的方式, 如:C /C+ VB,Java1.4 在win ,unix通吃, 便于移置!

18、0;     如果在現(xiàn)實(shí)中,測(cè)試沒(méi)有能找到所有的BUG,那可能就要用異常來(lái)幫忙了!      當(dāng)然,我也提出了我的觀點(diǎn), 我支持觀點(diǎn)6。理由如下:      assert只在debug標(biāo)志的時(shí)候有用,而在編譯release版本的時(shí)候不起作用。assert對(duì)于檢查硬編碼的錯(cuò)誤,是非常有用的,能夠及時(shí)的查處編碼的錯(cuò)誤。比如borland c+的類(lèi)庫(kù)源代碼中就有很多這樣的assert。但是assert     

19、不是萬(wàn)能的,因?yàn)橛泻芏噱e(cuò)誤的發(fā)生不是完全在編譯時(shí)發(fā)生的,而是運(yùn)行時(shí)的錯(cuò)誤。在release后,assert是不可能依賴的。那么,我們就需要exception這一機(jī)制來(lái)檢測(cè)運(yùn)行時(shí)錯(cuò)誤,并相應(yīng)的做出處理。當(dāng)然,在異常檢測(cè)和處理過(guò)程中還有許多需要討論的問(wèn)題,由于不是這一題目的范圍,我們沒(méi)有必要繼續(xù)討論得太多,但是,提出來(lái)希望大家注意:異常不是捕獲了就完成任務(wù)了,而要對(duì)于不同的情況,采取不同的處理辦法,千萬(wàn)不能只是捕獲,而不做任何處理,那樣和不捕獲異常沒(méi)有任何區(qū)別。      在題目剛剛提出的時(shí)候,選擇各種答案的人都有,所以,我有必要在這里把其他答案為

20、什么不能選的理由說(shuō)一下。      (a) if (!pParam)      return 0;      這是很多初級(jí)程序員常常采取的一種方式。返回值設(shè)為0。 因?yàn)楹瘮?shù)的返回值往往是計(jì)算的結(jié)果,不贊成把錯(cuò)誤標(biāo)志值和計(jì)算結(jié)果混在一起使用,容易造成使用者的誤會(huì)。當(dāng)然,在很多unix函數(shù)中,由于歷史原因,還存在很多這樣子的函數(shù),所以需要指出,不要沿用這種方式。      (b) if (!pPara

21、m)      return ERROR_PARAM;      b比a稍微好一點(diǎn)點(diǎn),返回了一個(gè)常量或者預(yù)定義的宏。 從返回值的字面上,調(diào)用者能知道發(fā)生了什么錯(cuò)誤,但是,這也不是一種好的方法。      (c) if (!pParam)      pParam = ""      .    

22、;  這是最不好的方式。直接給pParam賦予空字符串,然后繼續(xù)函數(shù)過(guò)程,這容易造成不可預(yù)料的后果,是程序不穩(wěn)定的根源。      (d) if (!pParam)      throw EXCEPTION_ERROR_PARAM;      拋出異常,剛剛已經(jīng)討論過(guò)了,不再贅述。      (e) if (!pParam)      M

23、essageBox(.);      這是一種比較可笑的方式,當(dāng)然也有不少人用。MessageBox是直接彈出一個(gè)對(duì)話框,告訴使用者,出錯(cuò)了。但是并不做任何處理,程序繼續(xù)往下執(zhí)行,直到出錯(cuò)崩潰。呵呵      (f) assert(!pParam);      斷言,剛剛已經(jīng)討論過(guò)了,不再贅述。      以上這個(gè)題目,引發(fā)了所有與會(huì)者的興趣,討論異常熱烈,最后,主持人也給出了自己的觀點(diǎn):d+f。

24、當(dāng)然這并不是標(biāo)準(zhǔn)答案,因?yàn)榫幊踢@一門(mén)課程本來(lái)就沒(méi)有什么標(biāo)準(zhǔn)答案,大家見(jiàn)仁見(jiàn)智,這個(gè)答案只是經(jīng)驗(yàn)的積累。      主持人緊接著列出了"編寫(xiě)優(yōu)質(zhì)無(wú)錯(cuò)代碼的經(jīng)驗(yàn)":      a.理想的編譯器和實(shí)際的編譯器      b.使用斷言      c.函數(shù)的界面設(shè)計(jì)      d.考慮風(fēng)險(xiǎn)    &

25、#160; e.態(tài)度的問(wèn)題      以上是本節(jié)的主要內(nèi)容。斷言,剛剛的問(wèn)題中已經(jīng)討論過(guò)了,來(lái)看看其他的內(nèi)容。      理想的編譯器和實(shí)際的編譯器:      題目二:      下面memcpy函數(shù)實(shí)現(xiàn)有什么問(wèn)題:      Void *memcpy(void *pvTo,void *pvFrom,size_t size)  

26、;    byte *pbTo=(byte *) pvTo;      byte *pbFrom=(byte *)pvFrom;      while(size - >0);      *pbTo+= *pbFrom+;      return pvTo;          

27、;  呵呵,粗略一看,這函數(shù)還真找不出問(wèn)題來(lái)。但是仔細(xì)看看,你就會(huì)發(fā)現(xiàn)while(size - >0);      這里多了一個(gè)分號(hào),導(dǎo)致下面的*pbTo+= *pbFrom+;不是在while循環(huán)中執(zhí)行多次,而是只執(zhí)行了一次。當(dāng)然這不是函數(shù)設(shè)計(jì)者的預(yù)期結(jié)果,而編譯器卻不會(huì)報(bào)告錯(cuò)誤,因?yàn)閣hile(size - >0);從語(yǔ)法上來(lái)講,并沒(méi)有錯(cuò)誤。這就是理想的編譯器和實(shí)際的編譯器的區(qū)別所在。      那么,該怎么檢查這種錯(cuò)誤呢?主持人提出了如下辦法:  

28、    while(size - >0) NULL; 可以加入NULL來(lái)解決空語(yǔ)句. 這樣子,當(dāng)你需要while(size - >0)        *pbTo+= *pbFrom+;      這種形式的時(shí)候,就不會(huì)發(fā)生錯(cuò)誤了,只需要用眼睛看看,就能發(fā)現(xiàn)了。兩點(diǎn)好處 1 無(wú)冗余代碼,2 使人更明白。減少風(fēng)險(xiǎn).      還有人會(huì)這么寫(xiě)    &

29、#160; if( (n=read(.) = 1) .      在這里,賦值符號(hào)=和判斷相等的符號(hào)=容易敲錯(cuò),而編譯器又檢查不出來(lái),可能就會(huì)有如下錯(cuò)誤:      If(ch = ).;這也是需要注意的問(wèn)題。      理想的編譯器和實(shí)際的編譯器小結(jié):      a.把屢次出錯(cuò)的合法的C習(xí)慣用法看成程序中的錯(cuò)誤      b.增強(qiáng)編譯器的警告級(jí)別

30、      c.使用其它的工具來(lái)檢查代碼 如 Lint 等      d.進(jìn)行單元測(cè)試      e.消除程序錯(cuò)誤的最好方法是盡可能早、盡可能容易地發(fā)現(xiàn)錯(cuò)誤,要尋求費(fèi)力最小的自動(dòng)查錯(cuò)的方法      f.努力減少程序員查錯(cuò)所需的技巧      使用斷言      題目三  

31、60;   下面函數(shù)實(shí)現(xiàn),哪一個(gè)好,為什么?      a.      char Uptolower(char ch)      if(ch >= A && ch <= Z)      return ch+=a-A;      return -1;    

32、60;       b.      char Uptolower(char ch)      assert(ch >= A && ch <= Z);      if(ch >= A && ch <= Z)      return ch+=a-A;    

33、  return ch;            c.      char Uptolower(char ch)      assert(ch >= A && ch <= Z);      return ch+(a-A);        

34、60;   分析:      a.該函數(shù)檢查ch是否在A.Z之間,如果是,則返回相應(yīng)的小寫(xiě)字符,如果不是,則返回-1。      缺點(diǎn)在于:把錯(cuò)誤標(biāo)志值和計(jì)算結(jié)果混在一起使用,容易造成使用者的誤會(huì)。      b.該函數(shù)使用了斷言,如果ch在A.Z之間則返回相應(yīng)的小寫(xiě)字符,如果不是,斷言會(huì)起作用,程序發(fā)生錯(cuò)誤并退出。而最后一個(gè)return ch;則是在release的時(shí)候,如果不是A.Z之間,則返回原來(lái)的字符。但是,從書(shū)寫(xiě)效率

35、上來(lái)說(shuō),這個(gè)函數(shù)稍微羅嗦了一點(diǎn)。因?yàn)樗貜?fù)使用了斷言和if判斷。      c.該函數(shù)也使用了斷言,返回相應(yīng)大寫(xiě)字母的小寫(xiě)字母。      使用斷言的好處:      a.暴露了調(diào)用者的錯(cuò)誤      b.便于調(diào)試      c.對(duì)代碼沒(méi)有代價(jià)      d.最少的處理代價(jià)  &

36、#160;   斷言使用舉例:      void memcpy(void * pvTo,void *pvFrom,size_t size)      void *pbTo= (byte *)pvTo;      void *pbFrom= (byte * pvFrom);      assert(pvTo !=NULL && pvFrom !=NULL);&#

37、160;     assert(pbTo >= pbFrom +size' 'pbFrom >= pbTo+size);                  使用斷言的規(guī)則:      a.要使用斷言對(duì)函數(shù)參數(shù)進(jìn)行確認(rèn)      b.要從程序中刪去無(wú)定義的特性或者在程序中使 用斷言來(lái)

38、檢查出無(wú)定義特性的非法使用      c.不要浪費(fèi)別人的時(shí)間-詳細(xì)說(shuō)明不清楚的斷言      d.消除所做的隱式假定,或者利用檢查其正確性      e.在進(jìn)行防錯(cuò)性程序設(shè)計(jì)時(shí),不要隱瞞錯(cuò)誤防錯(cuò)性程序設(shè)計(jì)雖然被譽(yù)為有較好的編碼風(fēng)格,但它卻隱瞞了錯(cuò)誤。      要記住,我們正在談?wù)摰腻e(cuò)誤決不應(yīng)該再發(fā)生,而對(duì)這些錯(cuò)所進(jìn)行的安全處理又編寫(xiě)無(wú)錯(cuò)代碼變得更加困難   

39、0;  f.要利用不同的算法對(duì)程序的結(jié)果進(jìn)行確認(rèn)      g.不要等待錯(cuò)誤發(fā)生,要使用初始檢查程序      斷言小結(jié):      a.要同時(shí)維護(hù)交付和調(diào)試兩個(gè)版本。封裝交付的版本,應(yīng)盡可能地使用調(diào)試版本進(jìn)行自動(dòng)查錯(cuò)。      b.斷言是進(jìn)行調(diào)試檢查的簡(jiǎn)單方法。要使用斷言捕捉不應(yīng)該發(fā)生的非法情況。不要混淆非法情況與錯(cuò)誤情況之間的區(qū)別,后者是在最終產(chǎn)品中必須處理的。 

40、0;    c.使用斷言對(duì)函數(shù)的參數(shù)進(jìn)行確認(rèn),并且在程序員使用了無(wú)定義的特性時(shí)向程序員報(bào)警。涵數(shù)定義得越嚴(yán)格,確認(rèn)其參數(shù)就越容易。      d.防錯(cuò)性程序設(shè)計(jì)會(huì)隱瞞錯(cuò)誤。在進(jìn)行防錯(cuò)編碼時(shí),如果”不可能發(fā)生”的情況確實(shí)發(fā)生了,要使用斷言進(jìn)行報(bào)警。      寫(xiě)到這里,我們初步探討了編寫(xiě)優(yōu)質(zhì)無(wú)錯(cuò)代碼的必要性,原則,和相關(guān)經(jīng)驗(yàn)。      留幾個(gè)練習(xí)題目,大家也參與一下討論吧。   

41、0;  練習(xí)題目1:      下面的memset函數(shù)實(shí)現(xiàn)有什么問(wèn)題?      void *memset(void *pv, byte b, size_t size)            byte *pb = (byte *)pv;      unsigned long l;     

42、 size_t sizeSize;      l = (b << 8) | b; /* 用4個(gè)字節(jié)拼成一個(gè)long */      l = (l << 16) | l;      pb = (byte *)longfill(long *)pb, l, size/4);      size = size % 4;      w

43、hile (size- > 0)      *pb+ = b;      return (pv);            練習(xí)題目2:      下面的代碼用memset將三個(gè)局部變量置為0,請(qǐng)問(wèn)可能會(huì)有什么問(wèn)題?      void DoSomeThing(.)  

44、60;         int i;      int j;      int k;      memset(&k, 0, 3*sizeof(int); / 將i,j,k置為0      .            練習(xí)題目

45、3:      定義結(jié)構(gòu)如下:      typedef struct            char c1;      char c2;      int n;      stru;      請(qǐng)問(wèn)

46、sizeof(stru)等于多少?并說(shuō)明理由。      練習(xí)題目4:      下面是C語(yǔ)言中兩種if語(yǔ)句判斷方式。請(qǐng)問(wèn)哪種寫(xiě)法更好?為什么?      int n;      if (n = 10) / 第一種判斷方式      if (10 = n) / 第二種判斷方式      練習(xí)題目5:

47、      下面的代碼有什么問(wèn)題?      void DoSomeThing(.)            char* p;      .      p = malloc(1024); / 分配1K的空間      if (NULL = p)

48、0;     return;      .      p = realloc(p, 2048); / 空間不夠,重新分配到2K      if (NULL = p)      return;      .         

49、0;  練習(xí)題目6:      下面的代碼有什么問(wèn)題?      char *DoSomeThing(.)            char str16;      .      return str;        &#

50、160;   練習(xí)題目7:      下面的代碼有什么問(wèn)題?      char *_strdup( const char *strSource )            static char strMAX_STR_LEN;      strcpy(str, strSource);    

51、;  return str;            練習(xí)題目8:      下面的代碼有什么問(wèn)題?并請(qǐng)給出正確的寫(xiě)法。      try      FILE* fp = fopen("c:1.dat");      if (NULL != fp)  

52、          .            fclose(fp);            except(EXCEPTION_EXECUTE_HANDLER)      編寫(xiě)優(yōu)質(zhì)無(wú)錯(cuò)的代碼(幻燈片完全版)http:/LinuxA 01-08-19 21:59 549p

53、ariesram-      介紹      編寫(xiě)優(yōu)質(zhì)無(wú)錯(cuò)代碼是否必要?      編寫(xiě)優(yōu)質(zhì)無(wú)錯(cuò)的代碼的核心思想      編寫(xiě)優(yōu)質(zhì)無(wú)錯(cuò)代碼的經(jīng)驗(yàn)      概述      概述各個(gè)主題      解釋各個(gè)單獨(dú)的主題如何組合在一起 

54、0;    編寫(xiě)優(yōu)質(zhì)無(wú)錯(cuò)的代碼是否必要 ?      編寫(xiě)優(yōu)質(zhì)無(wú)錯(cuò)的代碼的代價(jià)是什么?      代碼的質(zhì)量重要還是編寫(xiě)效率重要?在壓力的情況下,你會(huì)犧牲質(zhì)量來(lái)提高      效率么?      編寫(xiě)優(yōu)質(zhì)無(wú)錯(cuò)的代碼是否意味著效率的將低 ?      編寫(xiě)優(yōu)質(zhì)無(wú)錯(cuò)的代碼的核心思想   

55、60;  大家是否為提高代碼編寫(xiě)代碼質(zhì)量而努力?      習(xí)題      怎樣才能自動(dòng)地查出這個(gè)錯(cuò)誤!      怎樣才能避免這個(gè)錯(cuò)誤!      編寫(xiě)優(yōu)質(zhì)無(wú)錯(cuò)代碼的經(jīng)驗(yàn)      理想的編譯器和實(shí)際的編譯器      使用斷言     

56、 函數(shù)的界面設(shè)計(jì)      考慮風(fēng)險(xiǎn)      態(tài)度的問(wèn)題      Void *memcpy(void *pvTo,void *pvFrom,size_t size)      byte *pbTo=(byte *) pvTo;      byte *pbFrom=(byte *)pvFrom;    &#

57、160; while(size - >0);      *pbTo+= *pbFrom+;      return pvTo;            在判斷中使用無(wú)意的賦值。 If(ch = );      解決的辦法:1wile () NULL; 可以加入NULL來(lái)解決空語(yǔ)句 ;     

58、2 if ( =ch);      (strcpy函數(shù)的例子) while(*pchTo += *pchForm +) NULL;      while(*pchTo+=*pchFrom+)!=) NULL;      兩點(diǎn)好處 1 無(wú)冗余代碼,2 使人更明白。減少風(fēng)險(xiǎn).      把屢次出錯(cuò)的合法的C習(xí)慣用法看成程序中的錯(cuò)誤      增強(qiáng)編譯器

59、的警告級(jí)別      使用其它的工具來(lái)檢查代碼 如 Lint 等      進(jìn)行單元測(cè)試      小結(jié):      消除程序錯(cuò)誤的最好方法是盡可能早、盡可能容易地發(fā)現(xiàn)錯(cuò)誤,要尋求費(fèi)力      最小的自動(dòng)查錯(cuò)的方法      努力減少程序員查錯(cuò)所需的技巧   

60、0;  使用斷言      Char Uptolower(char ch)      if(ch >= A && ch <= Z)      return ch+=a-A;      return -1;            Char Uptolower(ch

61、ar ch)      assert(ch >= A && ch <= Z);      if(ch >= A && ch <= Z)      return ch+=a-A;      return ch;            Char U

62、ptolower(char ch)      assert(ch >= A && ch <= Z);      return ch+(a-A);            暴露了調(diào)用者的錯(cuò)誤      便于調(diào)試      對(duì)代碼沒(méi)有代價(jià)   &#

63、160;  最少的處理代價(jià)      void memcpy(void * pvTo,void *pvFrom,size_t size)      void *pbTo= (byte *)pvTo;      void *pbFrom= (byte * pvFrom);      assert(pvTo !=NULL && pvFrom !=NULL); 

64、60;    assert(pbTo >= pbFrom +size' 'pbFrom >= pbTo+size);                  要使用斷言對(duì)函數(shù)參數(shù)進(jìn)行確認(rèn)      要從程序中刪去無(wú)定義的特性或者在程序中使 用斷言來(lái)檢查出無(wú)定義特性的      非法使用 

65、     不要浪費(fèi)別人的時(shí)間-詳細(xì)說(shuō)明不清楚的斷言      消除所做的隱式假定,或者利用檢查其正確性      在進(jìn)行防錯(cuò)性程序設(shè)計(jì)時(shí),不要隱瞞錯(cuò)誤      防錯(cuò)性程序設(shè)計(jì)雖然被譽(yù)為有較好的編碼風(fēng)格,但它卻隱瞞了錯(cuò)誤。要記住,      我們正在談?wù)摰腻e(cuò)誤決不應(yīng)該再發(fā)生,而對(duì)這些錯(cuò)所進(jìn)行的安全處理又編寫(xiě)    &#

66、160; 無(wú)錯(cuò)代碼變得更加困難      要利用不同的算法對(duì)程序的結(jié)果進(jìn)行確認(rèn)      不要等待錯(cuò)誤發(fā)生,要使用初始檢查程序      斷言的使用與防錯(cuò)的程序設(shè)計(jì)沖突么?他們相適應(yīng)的范圍環(huán)境在什么呢?      斷言小結(jié):      要同時(shí)維護(hù)交付和調(diào)試兩個(gè)版本。封裝交付的版本,應(yīng)盡可能地使用調(diào)試版    

67、  本進(jìn)行自動(dòng)查錯(cuò)。      斷言是進(jìn)行調(diào)試檢查的簡(jiǎn)單方法。要使用斷言捕捉不應(yīng)該發(fā)生的非法情況。      不要混淆非法情況與錯(cuò)誤情況之間的區(qū)別,后者是在最終產(chǎn)品中必須處理的。      使用斷言對(duì)函數(shù)的參數(shù)進(jìn)行確認(rèn),并且在程序員使用了無(wú)定義的特性時(shí)向程      序員報(bào)警。涵數(shù)定義得越嚴(yán)格,確認(rèn)其參數(shù)就越容易。      防錯(cuò)性程序設(shè)

68、計(jì)會(huì)隱瞞錯(cuò)誤。在進(jìn)行防錯(cuò)編碼時(shí),如果”不可能發(fā)生”的情況      確實(shí)發(fā)生了,要使用斷言進(jìn)行報(bào)警。      函數(shù)的界面      Char *strdup(char *str)      Char * strNew;      strNew = (char *) maloc (strlen(str)+1);   &

69、#160;  Strcpy(strNew,str);      Return (strNew);            Char c ;      c=getchar();      if(EOF=c)      .      void s

70、trdup(const char* strsrc , char * strdes, size_t dessize );      Bool getchar(char * pch);      要使用不容易忽視錯(cuò)誤情況,不要在返回值中隱藏錯(cuò)誤代碼      void * realloc (void * pv , size_t size ); 是一個(gè)面面俱到的函數(shù)      realloc() cha

71、nges the size of the memory block pointed to by ptr      to size bytes. The contents will be unchanged to the minimum of      the old and new sizes; newly allocated memory will be      uninitialized. If ptr is NULL, the call

72、is equivalent to      malloc(size); if size is equal to zero, the call is equivalent      to free(ptr). Unless ptr is NULL, it must have been returned by an      earlier call to malloc(), calloc() or realloc().  

73、60;   不要編寫(xiě)多種功能集于一身的函數(shù)      void *memset( void *dest, int c, size_t count );      size_t count=10;      int setvalue=0xff;      memset(pdest,count,setvalue);      cha

74、r *copysubstr (char * strTo, char * strFrom , size_t size)            char * strStar= strTo;      ASSERT(size<=strlen(strFrom);            我的寫(xiě)法:Void memset( void *dest, byt

75、e c, size_t count );      不要模棱兩可,要明確地定義函數(shù)的參數(shù)。      編寫(xiě)函數(shù)使其在給定有效的輸入情況下不會(huì)失?。╰olower函數(shù))      函數(shù)界面小結(jié)      設(shè)計(jì)能夠低御錯(cuò)誤的界面并不困難,但這確實(shí)需要多加考慮并且愿意放棄      根深蒂固的編碼習(xí)慣。 只需簡(jiǎn)單地改變函數(shù)的界面,就可以使 程序員編

76、60;     寫(xiě)出正確的代碼。 關(guān)鍵概念是”盡可能地使一切清晰明了”。      最容易使用和理解的函數(shù)界面,是其中每個(gè)輸入和輸出參數(shù)都只代表一種      類(lèi)型數(shù)據(jù)的界面。把錯(cuò)誤碼值和其它的專用值混在函數(shù)的輸入和輸出參數(shù)      中,只會(huì)搞亂函數(shù)的界面。      設(shè)計(jì)函數(shù)的界面迫使程序員考慮所有重要細(xì)節(jié)(如錯(cuò)誤情況的處理),不  

77、    要使 程序員能夠很容易地忽視或者忘記有關(guān)的細(xì)節(jié)。      老要想到程序員調(diào)用所編函數(shù)的方式,找出可能使程序員無(wú)意引入錯(cuò)誤碼      的界面缺陷。尤其重要的是要爭(zhēng)取編出永遠(yuǎn)成功的函數(shù),使調(diào)用者不必進(jìn)      行相的錯(cuò)誤處理。      為了增加程序的或理解性從而減少錯(cuò)誤,要保證所編函數(shù)的調(diào)用能夠被必     

78、; 須閱讀這些調(diào)用的程序員所理解。莫明其妙的數(shù)字和布爾參數(shù)都與這一目      標(biāo)背道而馳,因此應(yīng)該給以消除。      分解多功能的函數(shù).取更專業(yè)的函數(shù)名不但可以增進(jìn)人們對(duì)它理解,而且      使我們可以更加嚴(yán)格的斷言自動(dòng)地檢查出調(diào)用錯(cuò)誤      為了向程序員展示出所編函數(shù)的適當(dāng)調(diào)用方法,要在函數(shù)的界面中通過(guò)注      解的方式詳細(xì)說(shuō)明。要

79、強(qiáng)調(diào)危險(xiǎn)的方面 。      考慮編寫(xiě)代碼的風(fēng)險(xiǎn)      如何做才能減少甚至消除風(fēng)險(xiǎn)      程序員忽視風(fēng)險(xiǎn)性。      肓目認(rèn)為,自已的程序不會(huì)錯(cuò)誤。程序員不會(huì)打算出錯(cuò)。出錯(cuò)后,也不吃      驚。      思想上有,不管作出哪種選擇,最后總能得到無(wú)錯(cuò)代碼。  

80、60;   Long 的位域有多長(zhǎng),ANSI并沒(méi)有對(duì)些做出標(biāo)準(zhǔn)      使用有嚴(yán)格定義的數(shù)據(jù)類(lèi)型 int32 ,_int64,_int16 (windows)      數(shù)據(jù)上溢與下溢      #define Max=255;      unsigned char ch      for(ch =0 ; ch <=Ma

81、x; ch+)                   經(jīng)常反問(wèn)自己: “這個(gè)變量或表達(dá)式會(huì)上溢或下溢嗎?”      一個(gè)”任務(wù)”應(yīng)一次完成      每個(gè)函數(shù)只完成它自己的任務(wù)      函數(shù)要符合它的設(shè)計(jì)原則:高內(nèi)聚, 有且只有一個(gè)任務(wù)。     

82、 違反原則,難以調(diào)試,測(cè)試等。難以閱讀。代碼難以重復(fù)利用      “?:” 運(yùn)算符也是一種if 語(yǔ)句      使用 “?:” 運(yùn)算符所存在的問(wèn)題是:由于它很簡(jiǎn)單,容易使用,看起來(lái)好象      是產(chǎn)生高效代碼的理想方法,因此程序員就不再尋找更好的解決方法了。更      嚴(yán)重的是,程序員會(huì)將if 版本轉(zhuǎn)換為 “? :”      unsigne

83、d uCycleCheckBox(unsigned uCur)      reurn (uCur<=1)? (uCur=1)? 2: (uCur+1);            避免使用嵌套的“? :”運(yùn)算符      每種特殊情況只能處理一次。      (C+的異常處理,結(jié)構(gòu)化異常處理,以及Java 中的機(jī)制 finally) &

84、#160;    避免使用有風(fēng)險(xiǎn)的語(yǔ)言慣用語(yǔ)      在某些程序員看來(lái),放棄任何可能獲得效率的機(jī)會(huì)似乎犯罪。要樹(shù)立:即使效      率可能會(huì)稍稍低一點(diǎn),也要使用安全的設(shè)計(jì)和實(shí)現(xiàn)來(lái)系統(tǒng)地減少風(fēng)險(xiǎn)性。      a=a+c/4 為變成 a=a+c>>2;      不一致性是編寫(xiě)正確代碼的障礙。     

85、急于改正的心里,在沒(méi)有規(guī)約的情況下,會(huì)造成很大的混亂。比起沒(méi)有改進(jìn)造      成了更大的損失。      編碼風(fēng)格如此,錯(cuò)誤處理如此;      避免調(diào)用返回錯(cuò)誤的函數(shù)      在設(shè)計(jì)函數(shù)時(shí)盡量避免返回錯(cuò)誤值,以免程序員錯(cuò)誤地處理或漏掉這些返回值      風(fēng)險(xiǎn)小結(jié)      在選擇數(shù)據(jù)類(lèi)型的時(shí)

86、候要謹(jǐn)慎。      由于代碼可能會(huì)在不理想的硬件上運(yùn)行,因此很可能算法是正確的而執(zhí)行起來(lái)      卻有錯(cuò)。所以要經(jīng)常詳細(xì)檢查計(jì)算結(jié)果和測(cè)試結(jié)果的數(shù)據(jù)類(lèi)型范圍是否上溢或      下溢。      每函數(shù)應(yīng)該只有一個(gè)嚴(yán)格定義的任務(wù),不僅如此,完成每個(gè)任務(wù)也應(yīng)只有一種      途徑。      If 語(yǔ)句是個(gè)警告信號(hào),說(shuō)明代碼所做的工作可能比所需要的要多。努力消除代      碼中每一個(gè)不必要的if 語(yǔ)句,經(jīng)常反問(wèn)自己:”怎樣改變?cè)O(shè)計(jì)從而刪掉這個(gè)特      殊

溫馨提示

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

最新文檔

評(píng)論

0/150

提交評(píng)論