BUG,規范,斷言和調試

發表于:2011-11-04來源:未知作者:領測軟件測試網采編點擊數: 標簽:Bug管理
對于BUG的自信 Donald E. Knuth(高德納)在TeX: The Program的前言中說: "我相信,在1985年11月27日,TeX代碼里面的最后一個BUG已經被發現和解決了。但是,如果代碼中仍舊有BUG,我很高興付給任何第一個發現BUG的人20.48美元(這是前一個金額

  對于BUG的自信

  Donald E. Knuth(高德納)在TeX: The Program的前言中說:

  "我相信,在1985年11月27日,TeX代碼里面的最后一個BUG已經被發現和解決了。但是,如果代碼中仍舊有BUG,我很高興付給任何第一個發現BUG的人20.48美元(這是前一個金額的兩倍,而且我計劃在一年內把它翻倍。你看,我很自信!)"

  想知道后來發生了什么嗎?

  在http://truetex.com/knuthchk.htm可以看到他寫出去的支票的金額是從2.56美元開始翻倍的。微基百科中關于這種支票的文章(http://en.wikipedia.org/wiki/Knuth_reward_check)說,截至2001年10月為止,他寫出去了超過兩千張這樣的支票,但是他的BUG支票是如此有名,以至于很多人把他的支票收藏起來而不是拿出去兌現(http://www.tug.org/whatis.html)。

  有多少程序員在發布產品的時候可以這樣自信地聲明產品沒有問題?

  遺憾的是,現在的程序員經常把發現BUG的責任推給測試人員——“不用擔心,測試人員會發現所有BUG的,這是他們的工作”。實際上,測試人員并沒有開發人員的條件,他們不可能進行源代碼級別的調試,很大程度上只能靠運氣——沒錯,是靠運氣,如果一個BUG很容易被發現,程序員不太可能自己沒有發現它——來發現BUG。

  還有一些人干脆就認為BUG是不可避免的,或者認為不值得這么精益求精(參見網易虛擬社區http://p5.club.163.com/viewArticleByWWW.m?boardId=clanguage&articleId=clanguage_108eacc622169e7&boardOffset=0的討論),但是實際上防止BUG出現的最好的時機,就是在編寫代碼的時候。在編寫代碼一段時間之后,即使是編寫者本人也可能需要一段時間來理解代碼(如果不習慣寫注釋的話,這段時間會更長),更別說定位問題所在了。在編寫代碼時,如果具有良好的習慣,可以免去很多在之后消滅BUG的困難。

  規范不是語法

  太多人把不要使用goto奉為圣旨,從來不想去打破。他們會爭論,goto會造成難以維護的難讀的代碼,以及使編譯器無法進行優化。這兩點在很大程度上是真的,但是也有使用goto可以增加程序可讀性和效率時候。在這種情況下,遵循“不使用goto語句”規范會產生更糟糕的代碼。

  一些人喜歡在成員函數后面加const,但是另外一些人沒有養成這個習慣。一個直接的結果就是,一些看起來對對象完全沒有影響的函數不能在const函數里面使用。這時候應該怎么辦?看看Paul DiLascia建議的,把this指針強行轉化為一個非const指針(http://www.microsoft.com/msj/archive/S126E.aspx)。如果函數實際上會對對象成員造成影響(例如CToolBar::GetItemRect),這也會帶來潛在危險。

  為了和ANSI標準之前編寫的代碼兼容,ANSI C中的memchr函數的聲明為

  void *memchr(

  const void *buf,

  int c,

  size_t count

  );

  這里c是一個字符。很明顯,標準為了兼容性放棄了明確性和更強的類型檢查。如果放棄兼容性,這個函數應該聲明為如下形式

  void *memchr( const void *buf, unsigned char c, size_t count);

  微軟的很多代碼使用一種叫做匈牙利表示法的命名規范。這使得標識符的含義和類型更加明確——但是這是從廣義的角度來說的??紤]如下函數聲明

  char *strcpy( char *strDestination, const char *strSource );

  如果嚴格遵循原始的匈牙利表示法,那么兩個參數的聲明應該是pch開頭。但是以str開頭給這兩個參數更多含義:它們指向以\0為結束符的字符串

  規范是用來在大部分時間里遵循,以及在可以得到更好的結果時打破的。

  編譯警告的意義

  智能化的編譯器開始將語法正確的語句列為警告:

  while(size-->0);//注意這里有個分號 *pTo++=*pFrom++;

  編譯器會報告空循環問題。

  但是對于以0結尾的字符串復制

  while(*pTo++=*pFrom++);

  ,這樣的警告是多余的。

  更加常見的警告是在條件判斷語句中

  if(ch='\0') EndOfString();

  為了繞過這個警告,需要添加額外的運算或者語句,或者更正錯誤的賦值。

  while((*pTo++=*pFrom++)!='\0')...{}if(ch=='\0')

  一些程序員甚至將比較語句修改成

  if('\0'==ch)

  這樣作的原因顯而易見:為了減少潛在的BUG。如果你的編譯器沒有這樣的警告,那么你可以使用一些工具來檢查那些語法正確但是有潛在BUG的代碼。LintProject (http://www.codeproject.com/tools/lintproject.asp)就是其中一個。但是,良好的編程習慣還是減少BUG出現的最好的方法。

  在覺得警告消息太煩人的時候,不妨想想編譯器的開發人員為什么要編寫這么多警告消息,而不是僅僅尋求關閉警告的方法。

  P.S. Visual C++的默認警告等級是3級。發布軟件之前應該改成4級,之后檢查所有的編譯警告。

  無處不在的斷言

  使用編譯器來捕獲BUG的主意很好,Visual Studio 2005甚至會報告定義的變量不符合命名規范(Warning 1 CA1709 : Microsoft.Naming : Correct the casing of type name 'welcome'.);但是我敢打賭你檢查BUG列表的時候,你會發現只有一小部分BUG會被編譯器抓到。很多BUG在程序運行過程中很少會出現,例如內存分配失敗的問題

  char* strBuffer=new char [length];

  MyZeroMemory(strBuffer,length);

  這段代碼在絕大多數情況下會成功,但是在虛擬內存不足的時候,Windows會報告“您的系統虛擬內存太低,WINDOWS會增加虛擬內存頁面文件的大小。在這個過程中,一些應用程序的內存請求會被拒絕”然后開始增加虛擬內存,在這個過程中,new這樣的內存分配可能會因為內存不足而失敗,而MyZeroMemory則可能會造成訪問越界。如果你足夠幸運,你會在產品發布之前發現這個BUG,否則,你的用戶會代替你發現這個BUG。要是用戶剛好沒有備份的習慣,丟失了幾十分鐘甚至是幾小時的工作進度,用戶會很生氣,后果很嚴重。

原文轉自:http://www.anti-gravitydesign.com

国产97人人超碰caoprom_尤物国产在线一区手机播放_精品国产一区二区三_色天使久久综合给合久久97