《C++程序設(shè)計(jì)》課件第6章_第1頁
《C++程序設(shè)計(jì)》課件第6章_第2頁
《C++程序設(shè)計(jì)》課件第6章_第3頁
《C++程序設(shè)計(jì)》課件第6章_第4頁
《C++程序設(shè)計(jì)》課件第6章_第5頁
已閱讀5頁,還剩49頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡(jiǎn)介

第6章異常和錯(cuò)誤6.1異常與bug

6.2異常的體系結(jié)構(gòu)6.3使用異常

6.4調(diào)試

本章小結(jié)

習(xí)題

增強(qiáng)錯(cuò)誤恢復(fù)能力是提高代碼健壯性最有力的途徑之一。遺憾的是,在現(xiàn)實(shí)中人們往往忽略錯(cuò)誤處理情況,就好像程序處在一個(gè)無錯(cuò)的狀態(tài)下進(jìn)行工作。檢查錯(cuò)誤是一個(gè)乏味的工作,而且會(huì)導(dǎo)致代碼膨脹。異常處理是C++具有的一項(xiàng)特點(diǎn),它能夠使程序中斷并且處理異常情況(通常是錯(cuò)誤),并且是以一種有序的、有條理的、一致的方式來處理。異常處理允許程序中的一個(gè)部分去發(fā)現(xiàn)并分派錯(cuò)誤情況,而另一部分去處理錯(cuò)誤。通常是某種類的代碼,也許是某個(gè)庫里的類和函數(shù),能夠監(jiān)測(cè)出錯(cuò)誤而不需要知道正確的處理策略。同樣,另一種類的代碼可以處理錯(cuò)誤而不需要具有監(jiān)測(cè)錯(cuò)誤的功能。C++的異常處理機(jī)制為程序員提供了一種處理錯(cuò)誤的方式,使他們能在給定的系統(tǒng)結(jié)構(gòu)中,以最自然的方式去處理這些錯(cuò)誤。異常機(jī)制也使處理錯(cuò)誤的復(fù)雜性更加清晰可見。6.1異?常?與?bug

在設(shè)計(jì)軟件系統(tǒng)的過程中,處理程序中的錯(cuò)誤(bug)和其他反常行為是最困難的部分之一。在大型軟件開發(fā)中,錯(cuò)誤是不可避免的,在設(shè)計(jì)和實(shí)現(xiàn)中,花在測(cè)試、查找和修改錯(cuò)誤上的開銷往往也是最大的。異常就是運(yùn)行時(shí)出現(xiàn)的不正常,例如運(yùn)行時(shí)耗盡了內(nèi)存或遇到意外的非法輸入,要打開的文件已經(jīng)不存在等。異常存在于程序的正常功能之外,并要求程序立即處理。在設(shè)計(jì)良好的系統(tǒng)中,異常是程序錯(cuò)誤處理的一部分。當(dāng)程序代碼檢查到無法處理的問題時(shí),異常處理就特別有用。在這種情況下,監(jiān)測(cè)出問題的那部分需要一種方法把控制權(quán)轉(zhuǎn)到可以處理這個(gè)問題的那部分程序。錯(cuò)誤監(jiān)測(cè)程序還必須指出具體出現(xiàn)了什么問題。

異常處理機(jī)制提供程序中錯(cuò)誤監(jiān)測(cè)和錯(cuò)誤處理部分之間的通信。C++中的異常處理由三方面組成,既throw、try和catch,即拋出異常和捕獲異常,并對(duì)異常進(jìn)行處理。如果在程序的代碼中出現(xiàn)了異常的情況,也就是說,通過當(dāng)前語境無法獲得足夠的信息以決定應(yīng)該采取什么樣的措施,程序員可以創(chuàng)建一個(gè)包含錯(cuò)誤信息的對(duì)象并把它拋出當(dāng)前語境,通過這種方式將錯(cuò)誤信息發(fā)送到更大范圍的語境中。這種方式被稱為“拋出一個(gè)異?!?,由關(guān)鍵字throw表示。如下所示:

classThrowError{constchar*consterrorData;public:ThrowError(constchar*constmsg=0):errorData(msg){}};voidh(){throwThrowError("exceptionhappened!");}intmain(){h();return0;}

上面的代碼中,ThrowError是一個(gè)普通的類,它的構(gòu)造函數(shù)接受一個(gè)char*類型的變量作為參數(shù)。在拋出一個(gè)異常時(shí),可以使用任意的類型(包括內(nèi)置類型),但通常應(yīng)當(dāng)為拋出的異常創(chuàng)建特定的類。如果在一個(gè)函數(shù)內(nèi)部拋出了異常,這個(gè)函數(shù)就會(huì)因?yàn)閽伋霎惓6顺?。如果不想因?yàn)橐粋€(gè)throw而退出函數(shù),可以在函數(shù)中試圖解決實(shí)際產(chǎn)生程序設(shè)計(jì)問題的地方和可能產(chǎn)生異常的地方設(shè)置一個(gè)try塊。這個(gè)塊被稱為try塊的原因是程序需要在這里嘗試著調(diào)用各種函數(shù)。try塊只是一個(gè)普通的程序塊,由關(guān)鍵字try引導(dǎo):

try{//有可能產(chǎn)生異常的各種函數(shù)調(diào)用

}

使用異常處理時(shí),可以將所有工作放入try塊中,然后在try塊的后面處理可能產(chǎn)生的異常。這樣一來,代碼將更容易編寫和閱讀,因?yàn)榇a的設(shè)計(jì)目標(biāo)不會(huì)被錯(cuò)誤處理所干擾。當(dāng)異常被拋出后就會(huì)在異常處理器(exceptionhandler)的地方終止,也就是在這個(gè)地方異常被處理。程序員需要為每一種要被捕獲的異常設(shè)置一個(gè)異常處理器。異常處理器緊接著try塊,由關(guān)鍵字catch標(biāo)識(shí):

try{//可產(chǎn)生異常的代碼

}catch(type1lx1){//處理type1類型的異常}catch(type2lx2){//處理type2類型的異常

}//…catch中的參數(shù)也可以省略,異常類型通常提供了對(duì)其進(jìn)行處理的足夠的信息。如果想捕獲所有類型的異常,用省略號(hào)代替異常處理器的參數(shù)列表就能實(shí)現(xiàn)這一點(diǎn):

catch(…){//處理所有捕獲的異常

}

由于省略號(hào)異常處理器能夠捕獲任何類型的異常,因此最好將它放在異常處理器列表的最后,從而避免它后面的處處理器接受不到任何的異常。由于省略號(hào)異常處理器不接受任何參數(shù),因此得不到任何有關(guān)異常的信息,也無法知道異常的類型,它是一個(gè)全能捕獲者。異常處理器必須緊跟在try塊之后,一旦某個(gè)異常被拋出,異常處理機(jī)制將會(huì)依次按照在原代碼中出現(xiàn)的順序查找最近的異常處理器,一旦找到匹配的異常處理器,就認(rèn)為該異常已經(jīng)被處理了而不再繼續(xù)查找下去。這就是異常匹配。捕捉異常與函數(shù)調(diào)用相似,捕捉異常需要傳入exception參數(shù),而函數(shù)調(diào)用也需要傳入?yún)?shù)。但異常的參數(shù)與函數(shù)參數(shù)有很大區(qū)別:異常的拋出者在拋出異常之后不再擁有程序控制權(quán),異常處理返回之后不再回到拋出地點(diǎn),而函數(shù)調(diào)用則能在函數(shù)體執(zhí)行之后獲得返回參數(shù)繼續(xù)執(zhí)行。

異常捕捉不能進(jìn)行隱式類型轉(zhuǎn)換,例如拋出一個(gè)int類型的異常不能被double類型的catch捕捉到。只有在繼承關(guān)系的異常對(duì)象被拋出時(shí),捕捉其父類對(duì)象的catch才能夠捕捉該異常。異常的參數(shù)傳遞總是通過拷貝傳遞的。異常拋出者拋出的異常對(duì)象首先被拷貝到一個(gè)臨時(shí)對(duì)象中,這個(gè)臨時(shí)對(duì)象隨后被傳給異常處理參數(shù)。因此,如果通過值的方式獲取異常,會(huì)發(fā)生兩次拷貝;通過傳引用的方式會(huì)發(fā)生一次拷貝;而傳指針的方式則是應(yīng)該避免使用的。因?yàn)橹羔樦赶虻膶?duì)象定義在異常拋出者體內(nèi),轉(zhuǎn)到異常處理體時(shí),異常拋出體作用結(jié)束,對(duì)象被銷毀,因此在異常處理中得到的對(duì)象指針指向的是一個(gè)已經(jīng)被銷毀的對(duì)象。

傳值方式的異常存在另一個(gè)問題:拋出的異常對(duì)象如果被一個(gè)捕捉父類對(duì)象的catch捕捉到,其拷貝僅僅拷貝父類的數(shù)據(jù),在異常處理體中,無法根據(jù)多態(tài)性動(dòng)態(tài)調(diào)用原始對(duì)象類的方法?;谝陨侠碛?,C++中最好使用傳引用的異常傳遞方式。有時(shí)如果想把異常推到調(diào)用鏈的更高層次上去處理,可以重新拋出異常。在這種情況下,省略號(hào)異常處理器正好符合這種要求。這種處理方法可以捕獲所有異常,清理相關(guān)資源,然后重新拋出該異常,以使得其他地方的異常處理器能夠處理該異常。在一個(gè)異常處理器內(nèi)部,使用不帶參數(shù)的throw語句可以重新拋出異常:catch(…){cout<<"anexceptionwasthrown"<<endl;//釋放資源

throw;

}6.2異常的體系結(jié)構(gòu)標(biāo)準(zhǔn)C++庫定義了自己的異常類,為了方便快捷,讀者可以使用標(biāo)準(zhǔn)C++的異常類,或從它們繼承來派生出自己的異常類。所有的標(biāo)準(zhǔn)異常類都是從exception類派生的。exception類的兩個(gè)主要派生類是logic_error和runtime_error,這兩個(gè)類在頭文件<stdexcept>中定義。logic_error類用于描述程序中出現(xiàn)的邏輯錯(cuò)誤,例如傳遞無效的參數(shù)。runtime_error是指運(yùn)行時(shí)發(fā)生的錯(cuò)誤,這些錯(cuò)誤由無法預(yù)料的事件所造成,例如硬件故障或內(nèi)存耗盡。標(biāo)準(zhǔn)異常類的繼承關(guān)系如表6.1所示。表6.1標(biāo)準(zhǔn)異常類繼承關(guān)系

可以把多個(gè)異常組成族系。構(gòu)成異常族系的一些示例有數(shù)學(xué)錯(cuò)誤異常族系和文件處理錯(cuò)誤異常族系。在C++代碼中把異常組在一起有兩種方式:異常枚舉族系和異常派生層次結(jié)構(gòu)。程序6.1是一個(gè)異常枚舉族系的例子。

【程序6.1】enumFileErrors{nonExist,wrongFormat,diskSeekError...};intf(){ try { //... throwwrongFormat; }catch(FileErrorsfe) { switch(fe) { casenonExist: //... casewrongFormat: //... casediskSeekError: //… } } //...}

在try塊中有一個(gè)throw,它拋擲一個(gè)FileErrors枚舉中的常量。這個(gè)拋擲可被catch(FileErrors)塊捕獲到,接著后者執(zhí)行一個(gè)switch,對(duì)照情況列表,匹配捕獲到的枚舉常量值。上面的異常族系也可按異常派生層次結(jié)構(gòu)來實(shí)現(xiàn),如程序6.2所示。

【程序6.2】classFileErrors{};classNonExist:publicFileErrors{};classWrongFormat:publicFileErrors{};classDiskSeekError:publicFileErrors{};intf(){ try { //... throwWrongFormat; } catch(NonExist) { //… } catch(DiskSeekError){ //… } catch(FileErrors) { //… } //…}

上面的各異常處理程序塊定義了針對(duì)類NonExist和DiskSeekError的派生異常類對(duì)象,針對(duì)FileErrors的異常處理,既捕獲FileErrors類對(duì)象,也捕獲WrongFormat對(duì)象。

異常捕獲的規(guī)則除了前面所說的,必須嚴(yán)格匹配數(shù)據(jù)類型外,對(duì)于類的派生,下列情況也可以捕獲異常:

(1)異常處理的數(shù)據(jù)類型是公有基類,拋擲異常的數(shù)據(jù)類型是派生類。

(2)異常處理的數(shù)據(jù)類型是指向公有基類的指針,拋擲異常的數(shù)據(jù)類型是指向派生類的指針。對(duì)于派生層次結(jié)構(gòu)的異常處理,catch塊組中的順序是重要的。因?yàn)椤癱atch(基類)”總能夠捕獲“throw派生類對(duì)象”,所以“catch(基類)”塊總是放在“catch(派生類)”塊的后面,以避免“catch(派生類)”永遠(yuǎn)不能捕獲異常。6.3使用異常程序6.3以一個(gè)計(jì)算器例子來說明如何在實(shí)際的編程中使用異常。

【程序6.3】#include<iostream>#include<cstdlib>#include<cctype>#include<string>usingnamespacestd;//DeclaretheerrorclassclassError{};//CalculatorclassdeclarationclassCalculator{intpos;stringexpress;intaddsub();intmultdiv();intnumber()throw(Error);public:Calculator(){}intCompute(conststring&str)throw(Error);};//Calculatorclassdefinition//以上為"Calculator.h"頭文件定義

#include"Calculator.h“intCalculator::Compute(conststring&str)throw(Error){ intretn=0; try { pos=0; express=str; retn=addsub();if(pos<express.length()&&express[pos]!='\0') throwError(); } catch(Error) { cout<<'\r'; while(pos--) cout<<''; cout<<"syntaxerror"<<endl<<'\a'; throw; } returnretn;}intCalculator::addsub(){ intretn=multdiv(); while(express[pos]=='+'||express[pos]=='-') { intop=express[pos++]; intopr2=multdiv(); if(op=='+') retn+=opr2; else retn-=opr2; } returnretn;}//Highestprecedence:multiply/divide.intCalculator::multdiv(){ intretn=number(); while(express[pos]=='*'||express[pos]=='/') { intop=express[pos++]; intopr2=number(); if(op=='*') retn*=opr2; else retn/=opr2; } returnretn;}intCalculator::number()throw(Error){ intretn;

if(express[pos]=='(') { pos++; retn=addsub(); if(express[pos++]!=')')//Musthave')' throwError(); }else{ //Extractthenumber. if(!isdigit(express[pos])) throwError(); charans[80]="0"; inti=0; while(isdigit(express[pos])&&pos<express.length()) ans[i++]=express[pos++]; ans[i]='\0'; retn=atoi(ans); }returnretn;}intmain(){ intanswer; do{ //Readanexpression cout<<"Enterexpression(0toquit):"<<endl; stringexpress; cin>>express;try { Calculatorcalc; answer=calc.Compute(express); if(answer!=0) cout<<answer<<endl; } catch(Error) { cout<<"Tryagain"<<endl; answer=1; } }while(answer!=0); return0;}

運(yùn)行示例結(jié)果如下:

程序6.3中,main()函數(shù)從控制臺(tái)讀取表達(dá)式,插入一個(gè)try塊中,并且實(shí)例化一個(gè)計(jì)算器對(duì)象。程序調(diào)用計(jì)算器對(duì)象的Compute()函數(shù),把字符串表達(dá)式作為一個(gè)參數(shù)來進(jìn)行傳遞。如果一切順利,Compute()函數(shù)將返回一個(gè)整數(shù)值,即表達(dá)式的結(jié)果。如果數(shù)值為0,程序?qū)?huì)終止;否則,程序?qū)@示這個(gè)數(shù)值并且請(qǐng)求下一個(gè)要計(jì)算的表達(dá)式。如果在計(jì)算過程中有錯(cuò)誤發(fā)生,計(jì)算器對(duì)象就會(huì)發(fā)出一個(gè)Error異常。main()函數(shù)將捕獲這個(gè)異常,顯示“重試”消息,并請(qǐng)求另一個(gè)表達(dá)式。Compute()成員函數(shù)初始化下標(biāo)數(shù)據(jù)成員,到表達(dá)式字符串中。插入一個(gè)try塊中,并且調(diào)用位于遞歸下降頂端的addsub()成員函數(shù)。如果上述過程的任何一個(gè)步驟碰到了表達(dá)式中存在的錯(cuò)誤,函數(shù)就會(huì)發(fā)出一個(gè)Error異常,并由Compute()成員函數(shù)所捕獲。當(dāng)Compute()捕獲到一個(gè)異常信息時(shí),就使用當(dāng)前下標(biāo)數(shù)據(jù)成員來顯示錯(cuò)誤是在表達(dá)式的何處被發(fā)現(xiàn)的。然后,Compute()函數(shù)重新發(fā)出異常,這樣main()函數(shù)也可以捕獲它了。同樣,如果沒有任何異常發(fā)出,Compute()函數(shù)會(huì)返回addsub()成員函數(shù)所返回的數(shù)值。6.4調(diào)試一個(gè)合格的程序員必須具有很好的調(diào)試程序的技能,調(diào)試技能的獲得要靠大量的編程經(jīng)驗(yàn)。初學(xué)編程的人都有很深的體會(huì),有時(shí)發(fā)現(xiàn)程序中的錯(cuò)誤是很難的,所以調(diào)試經(jīng)驗(yàn)的積累,其重要性甚至超過學(xué)習(xí)一門語言。不會(huì)調(diào)試的程序員就意味著他即使會(huì)一門語言,也不能編制出好的軟件。調(diào)試通常離不開編程工具的支持,即與集成開發(fā)環(huán)境密切相關(guān)。下面以VC++開發(fā)環(huán)境為例來介紹如何進(jìn)行調(diào)試。1.設(shè)置環(huán)境首先是對(duì)編譯器環(huán)境的設(shè)置。為了調(diào)試一個(gè)程序,首先必須使程序中包含調(diào)試信息。一般情況下,一個(gè)從AppWizard創(chuàng)建的工程中包含的DebugConfiguration自動(dòng)包含調(diào)試信息,但是Debug版本并不是程序包含調(diào)試信息的決定因素,程序設(shè)計(jì)者可以在任意的Configuration中增加調(diào)試信息,包括Release版本。為了增加調(diào)試信息,可以按照下述步驟進(jìn)行:打開Projectsettings對(duì)話框(可以通過快捷鍵Alt+F7打開,也可以通過IDE菜單Project/Settings打開),選擇C/C++頁,在Category中選擇general,則出現(xiàn)一個(gè)DebugInfo下拉列表框,可供選擇的調(diào)試信息顯示方式包括:●命令行Projectsettings說明?!駸oNone沒有調(diào)試信息?!?/ZdLineNumbersOnly:目標(biāo)文件或者可執(zhí)行文件中只包含全局和導(dǎo)出符號(hào)以及代碼行信息,不包含符號(hào)調(diào)試信息。●?/Z7C7.0-Compatible:目標(biāo)文件或者可執(zhí)行文件中包含行號(hào)和所有符號(hào)調(diào)試信息,包括變量名及類型、函數(shù)及原型等。●?/ZiProgramDatabase:創(chuàng)建一個(gè)程序庫(PDB),包括類型信息和符號(hào)調(diào)試信息?!?/ZIProgramDatabaseforEditandContinue:除了前面/Zi的功能外,這個(gè)選項(xiàng)允許對(duì)代碼進(jìn)行調(diào)試過程中的修改和繼續(xù)執(zhí)行。這個(gè)選項(xiàng)同時(shí)使#pragma設(shè)置的優(yōu)化功能無效。選擇Link頁,選中復(fù)選框“GenerateDebugInfo”,這個(gè)選項(xiàng)將使連接器把調(diào)試信息寫進(jìn)可執(zhí)行文件和DLL。如果C/C++頁中設(shè)置了ProgramDatabase以上的選項(xiàng),則可以選擇Linkincrementally。選中這個(gè)選項(xiàng),將使程序可以在上一次編譯的基礎(chǔ)上被編譯(即增量編譯),而不必每次都從頭開始編譯。2.設(shè)置斷點(diǎn)調(diào)試的最基本的方法就是設(shè)置斷點(diǎn)。斷點(diǎn)是調(diào)試器設(shè)置的一個(gè)代碼位置。當(dāng)程序運(yùn)行到斷點(diǎn)時(shí),程序中斷執(zhí)行,回到調(diào)試器。斷點(diǎn)是最常用的技巧。調(diào)試時(shí),只有設(shè)置了斷點(diǎn)并使程序回到調(diào)試器,才能對(duì)程序進(jìn)行在線調(diào)試。

(1)設(shè)置斷點(diǎn):可以通過下述方法設(shè)置一個(gè)斷點(diǎn)。首先把光標(biāo)移動(dòng)到需要設(shè)置斷點(diǎn)的代碼行上,然后按快捷鍵F9彈出Breakpoints對(duì)話框,方法是按快捷鍵Ctrl+B或Alt+F9,或者通過菜單Edit/Breakpoints打開。打開后點(diǎn)擊Breakat編輯框右側(cè)的箭頭,選擇合適的位置信息。一般情況下,直接選擇linexxx就足夠了。如果想設(shè)置不是當(dāng)前位置的斷點(diǎn),可以選擇Advanced,然后填寫函數(shù)、行號(hào)和可執(zhí)行文件信息。(2)去掉斷點(diǎn):把光標(biāo)移動(dòng)到給定斷點(diǎn)所在的行,再次按F9鍵就可以取消斷點(diǎn)。同前面所述,打開Breakpoints對(duì)話框后,也可以按照界面提示去掉斷點(diǎn)。條件斷點(diǎn):可以為斷點(diǎn)設(shè)置一個(gè)條件,這樣的斷點(diǎn)稱為條件斷點(diǎn)。對(duì)于新加的斷點(diǎn),可以單擊Conditions按鈕,為斷點(diǎn)設(shè)置一個(gè)表達(dá)式。當(dāng)這個(gè)表達(dá)式發(fā)生改變時(shí),程序就被中斷。

(3)數(shù)據(jù)斷點(diǎn):數(shù)據(jù)斷點(diǎn)只能在Breakpoints對(duì)話框中設(shè)置。選擇“Data”頁,就可彈出設(shè)置數(shù)據(jù)斷點(diǎn)的對(duì)話框。在編輯框中輸入一個(gè)表達(dá)式,當(dāng)這個(gè)表達(dá)式的值發(fā)生變化時(shí),數(shù)據(jù)斷點(diǎn)就到達(dá)。一般情況下,這個(gè)表達(dá)式應(yīng)該由運(yùn)算符和全局變量構(gòu)成。例如,在編輯框中輸入g_bFlag這個(gè)全局變量的名字,那么當(dāng)程序中有g(shù)_bFlag=!g_bFlag時(shí),程序就將停在這個(gè)語句處。(4)消息斷點(diǎn):VC也支持對(duì)Windows消息進(jìn)行截獲,截獲方式有兩種:窗口消息處理函數(shù)和特定消息中斷。在Breakpoints對(duì)話框中選擇Messages頁,就可以設(shè)置消息斷點(diǎn)。如果在Breakpoints對(duì)話框中寫入消息處理函數(shù)名,那么每次消息被這個(gè)函數(shù)處理,斷點(diǎn)就到達(dá)(筆者覺得如果采用普通斷點(diǎn)在這個(gè)函數(shù)中截獲,效果應(yīng)該一樣)。如果在下拉列表框中選擇一個(gè)消息,則每次這種消息到達(dá),程序就中斷。

3.Watch監(jiān)視

VC支持查看變量、表達(dá)式和內(nèi)存的值。所有這些觀察都必須是在斷點(diǎn)中斷的情況下進(jìn)行。觀看變量的值最簡(jiǎn)單,當(dāng)斷點(diǎn)到達(dá)時(shí),把光標(biāo)移到這個(gè)變量上,停留一會(huì)就可以看到變量的值。VC提供一種被稱為Watch的機(jī)制來觀看變量和表達(dá)式的值。在斷點(diǎn)狀態(tài)下,在變量上單擊右鍵,選擇QuickWatch,就彈出一個(gè)對(duì)話框,顯示這個(gè)變量的值。單擊Debug工具條上的Watch按鈕,就出現(xiàn)一個(gè)Watch視圖(Watch1,Watch2,Watch3,Watch4),在該視圖中輸入變量或者表達(dá)式,就可以觀察它們的值。注意:這個(gè)表達(dá)式不能有副作用,例如++運(yùn)算符絕對(duì)禁止用于這個(gè)表達(dá)式中,因?yàn)檫@個(gè)運(yùn)算符將修改變量的值,導(dǎo)致軟件的邏輯被破壞。

Watch監(jiān)視有以下三種:

1)Memory(內(nèi)存)監(jiān)視由于指針指向的是數(shù)組,Watch只能顯示第一個(gè)元素的值。為了顯示數(shù)組的后續(xù)內(nèi)容,或者要顯示一片內(nèi)存的內(nèi)容,可以使用Memory功能。在Debug工具條上點(diǎn)擊Memory按鈕將彈出一個(gè)對(duì)話框,在其中輸入地址,就可以顯示該地址指向的內(nèi)存的內(nèi)容。

2)?Varibles(變量)監(jiān)視單擊Debug工具條上的Varibles按鈕,將彈出一個(gè)對(duì)話框,顯示所有當(dāng)前執(zhí)行上下文中可見的變量的值。特別是當(dāng)前指令涉及的變量將以紅色顯示。

3)寄存器監(jiān)視單擊Debug工具條上的Reigsters按鈕,將彈出一個(gè)對(duì)話框,顯示當(dāng)前所有寄存器的值。4.進(jìn)程控制

VC允許被中斷的程序繼續(xù)運(yùn)行、單步運(yùn)行和運(yùn)行到指定光標(biāo)處,分別對(duì)應(yīng)快捷鍵F5、F10/F11和Ctrl+F10。各個(gè)快捷鍵的功能如下:

F5:繼續(xù)運(yùn)行。

F10:?jiǎn)尾剑绻婕暗阶雍瘮?shù),不會(huì)進(jìn)入子函數(shù)內(nèi)部。

F11:?jiǎn)尾剑绻婕暗阶雍瘮?shù),將進(jìn)入子函數(shù)內(nèi)部。

Ctrl+F10:運(yùn)行到當(dāng)前光標(biāo)處。

5.調(diào)用堆棧調(diào)用堆棧(CallStack)反映了當(dāng)前斷點(diǎn)處函數(shù)是被哪些函數(shù)按照什么順序調(diào)用的。單擊Debug工具條上的CallStack按鈕,將顯示CallStack對(duì)話框。在CallStack對(duì)話框中顯示了一個(gè)調(diào)用系列,最上面的是當(dāng)前函數(shù),往下依次是調(diào)用函數(shù)的上級(jí)函數(shù)。單擊這些函數(shù)名可以跳到對(duì)應(yīng)的函數(shù)中。

6.其他調(diào)試手段系統(tǒng)提供一系列特殊的函數(shù)或者宏來處理Debug版本相關(guān)的信息,如下:

TRACE:使用方法和printf完全一致,它在output框中輸出調(diào)試信息。

ASSERT:它接收一個(gè)表達(dá)式,如果這個(gè)表達(dá)式為TRUE,則無動(dòng)作;否則,中斷當(dāng)前程序的執(zhí)行。對(duì)于系統(tǒng)中出現(xiàn)這個(gè)宏導(dǎo)致的中斷,應(yīng)該認(rèn)為你的函數(shù)調(diào)用未能滿足系統(tǒng)調(diào)用此函數(shù)的前提條件。例如,對(duì)于一個(gè)還沒有創(chuàng)建的窗口調(diào)用SetWindowText等。VERIFY和ASSERT功能類似,所不同的是,在Release版本中,ASSERT不計(jì)算輸入的表達(dá)式的值,而VERIFY計(jì)算表達(dá)式的值。一個(gè)好的程序員不應(yīng)該把所有的判斷交給編譯器和調(diào)試器,應(yīng)該在程序中自己加以程序保護(hù)和錯(cuò)誤定位,具體措施包括:

(1)對(duì)于所有有返回值的函數(shù),都應(yīng)該檢查返回值,除非你確信這個(gè)函數(shù)調(diào)用絕對(duì)不會(huì)出錯(cuò),或者不關(guān)心它是否出錯(cuò)。

(2)一些函數(shù)返回錯(cuò)誤,需要用其他函數(shù)獲得錯(cuò)誤的具體信息。例如accept返回INVALID_SOCKET表示accept失敗,為了查明具體的失敗原因,應(yīng)該立刻用WSAGetLastError獲得錯(cuò)誤碼,并針對(duì)性地解決問題。(3)有些函數(shù)通過異常機(jī)制拋出錯(cuò)誤,應(yīng)該用TRY-CATCH語句來檢查錯(cuò)誤。程序員對(duì)于能處理的錯(cuò)誤,應(yīng)該自己在底層處理;對(duì)于不能處理的,應(yīng)該報(bào)告給用戶讓他們決定怎么處理。如果程序出了異常,卻不對(duì)返回值和其他機(jī)制返回的錯(cuò)誤信息進(jìn)行判斷,只會(huì)加大找錯(cuò)誤的難度。另外,VC中要編制程序不應(yīng)該一開始就寫cpp/h文件,而應(yīng)該首先創(chuàng)建一個(gè)合適的工程。因?yàn)橹挥羞@樣,VC才能選擇合適的編譯、連接選項(xiàng)。對(duì)于加入到工程中的cpp文件,應(yīng)該檢查是否在第一行顯式地包含stdafx.h頭文件,這是MicrosoftVisualStudio為了加快編譯速度而設(shè)置的預(yù)編譯頭文件。在這這個(gè)#include“stdafx.h”行前面的所有代碼將被忽略,所以其他頭文件應(yīng)該在這一行后面被包含。對(duì)于.c文件,由于不能包含stdafx.h,因此可以通過Projectsettings把它的預(yù)編譯頭設(shè)置為“不使用”,方法是:首先打開Projectsettings對(duì)話框,然后選擇C/C++,接著在Category中選擇PrecompilationHeader,最后選擇不使用預(yù)編譯頭。本章小結(jié)為了檢測(cè)異常,程序中使用try、catch和throw語句。異常處理使程序中錯(cuò)誤的檢測(cè)簡(jiǎn)單化,并提高了程序處理錯(cuò)誤的能力。編程技巧與注意事項(xiàng):

(1)所謂異常是指程序中有運(yùn)行錯(cuò)誤,程序應(yīng)能檢測(cè)錯(cuò)誤;

(2)?try語句使C++能夠進(jìn)行異常檢測(cè);

(3)?catch緊跟在try語句后面,以捕獲異常;

(4)通過程序中的throw語句報(bào)告異常;

(5)異常通過拋出一個(gè)類型和catch的參數(shù)相匹配而捕獲;(6)捕獲異常后,程序?qū)?zhí)行catch中的語句;

(7)如果程序拋出一個(gè)不能捕獲的異常,C++將執(zhí)行默認(rèn)異常處理函數(shù);

(8)調(diào)試是編程中非常重要的一項(xiàng)技能,找到程序中的錯(cuò)

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(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)論