国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 編程 > C++ > 正文

掌握C++Builder的調(diào)試藝術(shù)

2019-09-06 23:33:41
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

                    以代碼為基礎(chǔ)的調(diào)試方法
  程序的bugs越少,最終用戶(hù)對(duì)這個(gè)程序的評(píng)價(jià)越高。而開(kāi)發(fā)人員事先對(duì)bugs的處理越多,最終用戶(hù)能提供的關(guān)于bugs的信息就越多,也越準(zhǔn)確,這樣,開(kāi)發(fā)人員在接到最終用戶(hù)反映之后,就能夠快速找到出現(xiàn)bugs的那部分代碼,并以最快速度發(fā)布程序的升級(jí)包。

  在這份教程中,我們從最基本的部分開(kāi)始,逐步介紹許多在調(diào)試程序時(shí)“應(yīng)該做”或“不應(yīng)該做”的原則。正如你將看到的,這份教程中所指的“調(diào)試”這個(gè)詞所包含的意思很多,而不只是如大部分人所想到的--利用IDE集成的調(diào)試器的“調(diào)試”。我希望讀過(guò)這份教程之后,讀者可以在思路上有所收獲。

寫(xiě)易讀的代碼
  第一點(diǎn),大概也是最重要的一點(diǎn),就是寫(xiě)干凈易讀的代碼。易讀的代碼是很有價(jià)值的。請(qǐng)想象一下,如果隨便掃視一眼代碼或注釋?zhuān)湍芰⒖讨肋@段代碼的的作用,以及在寫(xiě)代碼的時(shí)候?yàn)槭裁匆@樣寫(xiě),當(dāng)時(shí)的思路是什么,那么就可以節(jié)約大量時(shí)間。這樣的代碼,在寫(xiě)的時(shí)候可能會(huì)稍稍慢一些,不過(guò),當(dāng)你調(diào)試程序時(shí),就不會(huì)花上幾個(gè)小時(shí)來(lái)尋找bugs,相反,你可以快速,簡(jiǎn)單的完成除錯(cuò)工作。這時(shí),你就會(huì)覺(jué)得多花一些時(shí)間使程序易讀是很值得的。

  所以,我推薦你在寫(xiě)程序的時(shí)候,應(yīng)該養(yǎng)成自己的風(fēng)格,或是讀一讀Scott的關(guān)于代碼風(fēng)格的文章。

使用Exceptions和Exception的處理方法
  我們教程的下一步,仍然是以代碼為基礎(chǔ)的。因?yàn)槌ヒ恍┥贁?shù)的情況,開(kāi)發(fā)人員不可能總是依靠于集成的調(diào)試工具。所以,學(xué)會(huì)用其它的方法來(lái)找到煩人的bugs是很重要的。一些重要的、處理的錯(cuò)誤可能會(huì)在窗體之外發(fā)生。在C++標(biāo)準(zhǔn)制定出來(lái)之前的黑暗日子里,在程序里面發(fā)出發(fā)生錯(cuò)誤的信號(hào),通常是通過(guò)返回錯(cuò)誤代碼完成的(現(xiàn)在這種方法仍然應(yīng)用于OLE技術(shù)和一些Winapi函數(shù)),這樣的處理方法很容易就會(huì)被忽略。(比如說(shuō),你經(jīng)常檢查winapi函數(shù)的返回值嗎?)所以,出現(xiàn)問(wèn)題的可能性并不小。由于以上的原因,我們需要一個(gè)這樣的機(jī)制,它能讓我們不能忽略這些錯(cuò)誤,而且,這個(gè)機(jī)制應(yīng)該能被我們控制和自定義的。在這樣的需求下,異常處理機(jī)制出現(xiàn)了。需要一個(gè)特殊的錯(cuò)誤類(lèi)型嗎?簡(jiǎn)單,定義一個(gè)新的異常類(lèi)型就行了(和定義一個(gè)類(lèi)的方法差不多),然后拋出(throw)它。下面這個(gè)例子說(shuō)明了這一過(guò)程。

  例1:

  //----------------------------------------------------------------

  class MyException

  {

  public:

   AnsiString iMessage;

   MyException(AnsiString Message) { iMessage=Message;}

  };

  throw new MyException(“Test Exception Message”);

  //---------------------------------------------------------------

  就是它!(不是十分好,下面我們會(huì)繼續(xù)完善它)。簡(jiǎn)單高效,而且便于自定義。也許你現(xiàn)在會(huì)問(wèn):“我可以使拋出異常了,但是,怎么控制它們呢?我的意思是,我想在代碼的最前面排除異常。”C++Builder為我們中定義了try {} catch (...) {}機(jī)制。這和我們剛剛定義的異常機(jī)制的結(jié)構(gòu)很相似。這個(gè)機(jī)制完全可以按照需要自定義。要使用異常處理了,只要把要執(zhí)行的代碼放到try塊里面,為了讓程序知道出現(xiàn)異常后應(yīng)該做什么,還需要定義一個(gè)catch()或是__finally塊。catch()語(yǔ)句里面可以指定一個(gè)要捕捉的類(lèi)型或是變量(比如例1,就是catch(MyException &E){ /* 異常處理代碼/}這個(gè)機(jī)制很強(qiáng)大,甚至可以用它來(lái)捕捉樹(shù)結(jié)構(gòu)或是繼承類(lèi)的異常,如果捕捉了基類(lèi)的異常,它就能捕捉到繼承這個(gè)基類(lèi)的所有的類(lèi)的異常。比如,在VCL中,所有的異常都是繼承于Exception類(lèi)。所以,catch(Exception& E)可以捕捉到除了EsocketError的所有VCL異常。(這點(diǎn)請(qǐng)?zhí)貏e注意,以后還將繼續(xù)討論。)為了讓這個(gè)機(jī)制更強(qiáng)大,C++Builder中還定義了catch(…)語(yǔ)句。(沒(méi)錯(cuò),就是三個(gè)點(diǎn))使用這條語(yǔ)句可以捕捉到所有的異常。還有更多的功能嗎?當(dāng)然,你可以添加更多的catch()語(yǔ)句,可以向使用if...else if...語(yǔ)句那樣使用它。注意,在一系列的catch()語(yǔ)句中,錯(cuò)誤不會(huì)被重復(fù)的捕捉,也就是說(shuō),如果前面的catch()語(yǔ)句捕捉到了錯(cuò)誤,后面的catch()語(yǔ)句將不會(huì)捕捉這條錯(cuò)誤。

  例2:

  //----------------------  

  try

  {

   // 正常代碼

  }

  catch(EDBEngineError &E)

  {

   // 處理數(shù)據(jù)庫(kù)引擎錯(cuò)誤

  }

  catch(EExternalError &E)

  {

   // 處理窗口類(lèi)的錯(cuò)誤

  }

  catch(Exception &E)

  {

   // 處理所有的VCL錯(cuò)誤

  }

  //----------------------

  請(qǐng)看例2,它的代碼運(yùn)行流程是這樣的:“錯(cuò)誤是EDBEngineError嗎?是->處理它。不是->運(yùn)行下一個(gè)catch語(yǔ)句”“錯(cuò)誤是EExternalError嗎?是-〉處理它。不是-〉運(yùn)行下一個(gè)catch語(yǔ)句”等等。

  這個(gè)機(jī)制還有更多的功能。如果你想處理異常,但是不想在處理的位置停止,那么可以重新拋出異常。這時(shí),程序?qū)⒗^續(xù)尋找下一個(gè)catch()語(yǔ)句來(lái)處理這個(gè)異常。這個(gè)方法和“throw”差不多。這樣,你處理過(guò)的異常會(huì)再次被拋出,繼續(xù)尋找下一個(gè)catch語(yǔ)句來(lái)處理它。

  最后一個(gè)要說(shuō)的是__finally(這不是標(biāo)準(zhǔn)的用法,是Borland添加的一個(gè)好方法),在__finally{}程序塊中代碼,無(wú)論是否發(fā)生異常都會(huì)被執(zhí)行。這是一個(gè)清理程序中使用new分配的本地變量,設(shè)置用作旗標(biāo)的變量值為正常的好位置。(比如,把一個(gè)等待狀態(tài)的光標(biāo)圖標(biāo)設(shè)置為正常光標(biāo)。)

  就是這些了。有時(shí)間的話(huà),請(qǐng)看看C++Builder幫助文件中的Exception類(lèi)以及繼承Exception的類(lèi)。這些將對(duì)于理解本節(jié)所說(shuō)的內(nèi)容有很大幫助。

使用記錄機(jī)制
  你不可能總是用調(diào)試器來(lái)調(diào)試代碼,在某些情況下,可能無(wú)法使用內(nèi)部集成的調(diào)試器,這時(shí)候,你就不得不依靠其他手段調(diào)試程序了。(比如:Windows NT服務(wù)程序,ISAPI/CGI程序,實(shí)時(shí)應(yīng)用程序等等)。這時(shí)候,有經(jīng)驗(yàn)的程序員可能會(huì)借助古老的調(diào)試方法,例如,使用一些分類(lèi)的記錄機(jī)制來(lái)確定程序?qū)嶋H運(yùn)行的過(guò)程。我們很幸運(yùn),現(xiàn)在有一系列的方法可以簡(jiǎn)單的完成這樣的工作。下面將介紹3種我最喜歡的方法。

  第一個(gè):OutputDebugString。(WinAPI: VOID OutputDebugString(LPCTSTR lpOutputString);)很幸運(yùn),微軟徹底的實(shí)現(xiàn)了調(diào)試子系統(tǒng)。它包括的一些特點(diǎn)可能讓你想把自己的記錄系統(tǒng)扔掉。應(yīng)用程序在調(diào)試器進(jìn)程中運(yùn)行時(shí)OutputDebugString將用C字符串把調(diào)試器輸出的信息打印出來(lái)。如果程序沒(méi)有在調(diào)試器進(jìn)程中運(yùn)行,它將忽略這些調(diào)用。它會(huì)很好的在客戶(hù)的機(jī)器上運(yùn)行,不會(huì)彈出信息窗口。如果在發(fā)布給客戶(hù)的時(shí)候,忘記去掉這些代碼程序僅僅會(huì)變慢一點(diǎn),不會(huì)有別的不良后果。

  第二個(gè)方法:使用了GExperts,通過(guò) dbugint.pas接口進(jìn)行調(diào)試。它是個(gè)可以稱(chēng)之為偉大的程序,你可以把它分發(fā)給客戶(hù)。和OutputDebugString一樣,如果客戶(hù)沒(méi)有這個(gè)程序,它就根本什么也不作。(它會(huì)自動(dòng)檢測(cè)機(jī)器上是否安裝了客戶(hù)端)。要使用dbugintf,它很容易被加入到你的工程中,加入#include "dbugintf.HPp"(要把它加入工程,然后會(huì)編譯它的pascal文件)。然后,你就可以直接使用SendDebug(要送到記錄文件的字符串); 或者,你需要它更機(jī)警一些,可以使用SendDebugEx(它給TMsgDlgType增加了一個(gè)新的消息類(lèi)型)SendMethodEnter, SendMethodExit, SendSeparator等等(用法都差不多)。如果你打算給最終用戶(hù)分發(fā)客戶(hù)端 (Gdebug.exe),不要忘記include所需要的程序包。GExperts可以在http://www.gexperts.org 得到,它是免費(fèi)的。

  第三個(gè),大概是最艱苦的方法,就是使用你自己的記錄控制。這個(gè)方法可能不是你想象的這么簡(jiǎn)單。你可能首先會(huì)想到“在窗體上扔一個(gè)RichEdit,把它設(shè)置為只讀的,然后往里面寫(xiě)記錄”是這樣吧?理論上不錯(cuò),但是,實(shí)施起來(lái)...首先,使用RichEdit控件來(lái)做記錄,會(huì)大大降低應(yīng)用程序的速度,還會(huì)在內(nèi)存中造成碎片,甚至丟失內(nèi)存。通常,在運(yùn)行10分鐘左右之后,會(huì)使整個(gè)計(jì)算機(jī)的速度變慢!(這樣做簡(jiǎn)直是在犯罪!)所以,如果你希望在自己的記錄中能夠使用彩色和圖標(biāo),那么最好自己創(chuàng)建一個(gè)組件。如果沒(méi)有這么高的要求,那么有一個(gè)簡(jiǎn)單有效的方法,就是使用ListBox控件作記錄,把ListBox的Style屬性設(shè)置為lbOwnerDrawFixed,這樣句柄將會(huì)自繪。(GExperts的控制臺(tái)就是用這樣的方法制作的)。

將記錄和異常處理結(jié)合使用
  你不用總是擔(dān)心可能會(huì)發(fā)生什么偶然的異常。一般來(lái)說(shuō),通過(guò)很多的bugs測(cè)試后(盡量折磨程序,看看它會(huì)不會(huì)崩潰),應(yīng)用程序在運(yùn)行是應(yīng)該不會(huì)出現(xiàn)什么錯(cuò)誤。下面的這個(gè)技術(shù),建議組件開(kāi)發(fā)者,在第一次把組件放在IDE環(huán)境測(cè)試的時(shí)候,很應(yīng)該遵守。一個(gè)在IDE中產(chǎn)生的異常會(huì)導(dǎo)致很多問(wèn)題,甚至可能無(wú)法重新啟動(dòng)IDE也不能恢復(fù)。這個(gè)技術(shù)很簡(jiǎn)單。在代碼中每一個(gè)函數(shù)或是主要的函數(shù)中加入:

  try

  {

   //函數(shù)的代碼

  }

  catch(Exception &E)

  {

  SendDebugMessage(“Exception caught in classname::functionname of type:” +E.ClassName()

  +” with the message:”+E.Message);

  };

  (把字符串中classname 和 functionname 替換成相應(yīng)的類(lèi)名和函數(shù)名。在出現(xiàn)錯(cuò)誤時(shí),你會(huì)立刻知道錯(cuò)誤發(fā)生的位置。這樣也就不至于強(qiáng)制重起IDE的了。

  現(xiàn)在,讓我們看看前面的內(nèi)容, ClassName()給了我們什么樣的幫助呢?它只是用于返回字符串“Exception”嗎?每一次,E都被聲明為異常類(lèi)型?這是VCL另一個(gè)優(yōu)秀的地方,所有的類(lèi)都從TObject繼承,所以,這些類(lèi)都能自動(dòng)獲得正確的類(lèi)型和基類(lèi)的類(lèi)型,所有的更多的信息都可以在這里找到。(請(qǐng)參見(jiàn)TObject的幫助)所以,盡管我們使用了Exception &E,其中的E.ClassName()將返回捕獲到的產(chǎn)生異常的實(shí)際類(lèi)名。得到這些好處需要付出的代價(jià)是編譯出來(lái)的可執(zhí)行文件變大了一些。所有的Delphi/CBuilder用戶(hù)都注意到了這一點(diǎn),但是他們說(shuō),沒(méi)有付出就沒(méi)有收獲。在http://www.bytamin-c.com/的howto欄目可以看到Xiphias的一系列文章。其中,他提到了使用TStringList作記錄的方法:先將錯(cuò)誤通過(guò)TStringList的Add方法加入到StringList里面,然后使用SaveToFile保存到硬盤(pán)上。不過(guò)要注意在程序結(jié)束的時(shí)候不要忘記使用SaveToFile()方法把TStringList保存起來(lái)。或者,也可以每次捕捉到異常之后都保存一次。

在代碼外部進(jìn)行異常處理
  這是使用代碼處理異常的最后一節(jié),以后,我們將使用IDE的調(diào)試工具。但是,這節(jié)中講到的方法在處理致命錯(cuò)誤時(shí)是很重要的。比如說(shuō):可以顯示一個(gè)包含了錯(cuò)誤信息的對(duì)話(huà)框,這樣,用戶(hù)報(bào)告bugs的時(shí)候會(huì)清除的多。你肯定不想聽(tīng)到用戶(hù)報(bào)告說(shuō):“啊,這有個(gè)對(duì)話(huà)框,上面寫(xiě)著什么地址發(fā)生了錯(cuò)誤”。有個(gè)好辦法能改善這種狀況,請(qǐng)往下面看。

  第一步:在主窗體(工程設(shè)置里面,自動(dòng)創(chuàng)建的第一個(gè)窗體)中創(chuàng)建這樣一個(gè)函數(shù):

  void __fastcall AppLevelExceptionHandler(TObject *Sender, Exception *E)

  {

  }

  然后,在里面加上顯是錯(cuò)誤(E->Message)的代碼,錯(cuò)誤類(lèi)型(記住前面提到過(guò)的E.ClassName())以及其他需要的細(xì)節(jié)信息。

  第二步:把它與系統(tǒng)掛鉤。很簡(jiǎn)單,只需要在窗體的OnCreate事件中加入這行:

  Application->OnException=AppLevelExceptionHandler;

  在這行代碼上,不要吝嗇,因?yàn)榧由纤旧暇涂梢哉f(shuō)所有的錯(cuò)誤都不會(huì)漏掉了。無(wú)論在任何地方發(fā)生的錯(cuò)誤都可以被捕捉到。

  現(xiàn)在,所有以代碼為基礎(chǔ)的調(diào)試方法你都學(xué)會(huì)了,馬上把他們加入到你的工程里去吧。最好能把它們變?yōu)槟愕牧?xí)慣。這將對(duì)你的程序有很大幫助。
發(fā)表評(píng)論 共有條評(píng)論
用戶(hù)名: 密碼:
驗(yàn)證碼: 匿名發(fā)表

圖片精選

主站蜘蛛池模板: 耒阳市| 浮山县| 淮北市| 滦平县| 邵武市| 盐山县| 丰都县| 麻城市| 奈曼旗| 禹城市| 延边| 星座| 建水县| 宜章县| 定南县| 武夷山市| 随州市| 中阳县| 古蔺县| 和田县| 平顶山市| 柘荣县| 凉山| 息烽县| 红安县| 吉木乃县| 平果县| 平顺县| 巢湖市| 广丰县| 宁安市| 随州市| 北宁市| 阿克陶县| 神池县| 册亨县| 台州市| 青海省| 泗水县| 石棉县| 绍兴县|