調試經驗總結:VC下的錯誤對話方塊

來源:互聯網
上載者:User

這裡所說的VC下的錯誤對話方塊時指在VC中開調試器運行程式時,IDE彈出的對話方塊。

1.不是錯誤的錯誤:斷言 .

將斷言視為錯誤其實有點可笑,但是因為有些同學甚至不知道這個,所以我稍微提一下。斷言對話方塊大致上類似於:

斷言對話方塊是由assert引起的,在對話方塊上通常會給出運算式,例如assert( 0 ); 彈出對話方塊時就會將0這個運算式顯示出來(Expression:0)。關於assert的具體資訊建議自己google。這裡稍微提一下一個技巧:有時候為了讓assert提供更多的資訊,我們可以這樣寫一個assert:

assert( expression && "Function : invalid argument!" );

因為字串被用在布林運算式中時,始終為true,不會妨礙對expression的判斷,當斷言發生時(expression為false) 時,斷言對話方塊上就會顯示這個字串,從而方便我們調試。

要解決這個問題,首先要確定斷言發生的位置,如果是你自己設定的斷言被引發,就很好解決,如果是系統內部的函數產生的,那麼一般是因為你傳入的函數參數無效引起。

 2.記憶體相關:最簡單的非法訪問:

C、C++程式中經常誤用無效的指標,從而大致各種各樣的非法記憶體訪問(寫/讀)。最簡單的情況類似於:

這樣的情況由類似以下代碼引起:

char *p = 0;

*p = "a";

當你看到類似於“寫入位置XXXX時發生存取違規“時,那麼你大致可以斷定,你的程式在某個地方訪問到非法記憶體。開調試器對呼叫堆疊進行跟蹤即可找出錯誤。

3.記憶體相關:不小心的棧上數組越界:

當你寫下類似以下的代碼時:

char str[3];

strcpy( str, "abc" );

就將看到如下的對話方塊:

 

對話方塊大致的意思就是說str周圍的棧被破壞了,因為str本身就被放在棧上,所以strcpy(str,"abc")多寫入的""就寫到非法的棧地區。看到這樣的對話方塊可以根據呼叫堆疊定位到錯誤發生的函數,然後檢查此函數內部定義的數組訪問,即可解決問題。

 4.記憶體相關:不小心的堆上數組越界:
並不是每次數組越界都會得到上面所描述的錯誤,當數組是在堆上分配時,情況就變得隱秘得多:

char *str = new char [2];

strcpy( str, "ab" ); //執行到這裡時並不見得會崩潰

delete [] str;//但是到這裡時就肯定會崩潰

以上代碼導致的錯誤對話方塊還要詭異些:

似乎不同的DAMAGE對應的錯誤號碼(這裡是47)都不一樣,因為這裡的錯誤發生在delete,而delete跟new很可能在不同的地方,所以這個錯誤調試起來不是那麼容易,很多時候只能靠經驗。

當看到類似的對話方塊時,根據呼叫堆疊跟到delete時,你就可以大致懷疑堆上數組越界。

 

5.調用相關:函數呼叫慣例帶來的錯誤:

這是所有我這裡描述的錯誤中最詭異的一種,先看下對話方塊大致的樣子:

對話方塊大致的意思就是說(沒開調試器時對話方塊樣式可能不一樣),通過函數指標調用某個函數時,函數指標的類型(函數原型)可能與函數指標指向的函數的類型不一樣。這裡的類型不一致主要是呼叫慣例(call conversation)不一樣。如果函數類型(參數個數,傳回值)不一樣,一般不會出錯。

呼叫慣例是指調用一個函數時,函數參數的壓入順序、誰來清理棧的內容等。例如預設的C、C++呼叫慣例__cdecl,對於函數的參數是從右往左壓入。而__stdcall(WIN API的呼叫慣例)則是從左向右壓。我這裡所說的函數類型不一樣,就是指一個函數是使用__cdecl,還是__stdcall。例如以下代碼:

#include <iostream> 

void __stdcall show( const char *str ) 





void __stdcall show2() 





int main() 



typedef void (*Func)( const char *); 

void *p = show; 

Func my_func = (Func) p; 

my_func( "kevin" ); 

return 0; 



 

因為Func預設地被處理為__cdecl,而show是__stdcall的,所以當通過函數指標my_func時,就導致了以上對話方塊的出現。但是當p指向show2時,又不會出錯,這是因為show2沒有參數,不同的呼叫慣例不影響這個規則。

6.異常相關:預設終止程式

當我們使用C++庫時,因為庫本身可能會拋出C++異常,如果你不捕獲這個異常,那麼C++預設就會調用abort(或者exit)函數終止程式。例如:

  

void test()
{
    throw std::exception( "some exceptions" );
}

 

當你調用test函數時,如果不catch這個異常,開調試器就會得到類似的錯誤對話方塊:

 

而如果不開調試器,則會得到:

 

當你看到類似於“This application has requested the Runtime to terminate it…”之類的字眼時,那就表明程式調用了abort(或exit)函數,導致程式異常終止。其實這個錯誤只要開調試器,一般可以準確定位錯誤的發生點。



轉自:http://www.kuqin.com/windows/20080504/7812.html

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.