Visual Studio原生开发的10个调试技巧
最近碰巧讀了Ivan Shcherbakov寫的一篇文章,《11個強大的Visual Studio調(diào)試小技巧》。這篇文章只介紹了一些有關(guān)Visual Studio的基本調(diào)試技巧,但是還有其他一些同樣有用的技巧。我整理了一些Visual Studio(至少在VS 2008下)原生開發(fā)的調(diào)試技巧。(如果你是工作在托管代碼下,調(diào)試器會有更多的特性,在CodeProject中有介紹它們的文章),下面是我的整理的一些技巧:
?
技巧1: 異常中斷
在處理被調(diào)用之前,異常發(fā)生時可以 啟動調(diào)試器進行中斷,可以讓你在異常發(fā)生后立即調(diào)試程序。操作調(diào)用棧便于你去查找異常發(fā)生的根本原因。
Vistual Studio允許你去指定想要中斷的異常類型或者特殊異常。選擇菜單Debug>Exceptions彈出對話框,你可以指定原生的(或者托管的)異常,除了調(diào)試器自帶的一些默認異常,你還可以添加自己的自定義異常。
下面是一個std::exception 異常拋出時調(diào)試器中斷的例子。
更多閱讀:
- 1.??異常拋出時如何中斷
- 2.??如何添加新的異常
?
技巧2:Watch窗口中的偽變量
Watch窗口或QuickWatch對話框提供一些特定的(調(diào)試器可識別的)變量,被稱為偽變量。文檔包含以下:
- $tid—–當前線程的線程ID
- $pid——進程ID
- $cmdline———-啟動程序的命令行字符串
- $user———-正在運行程序的賬戶信息
- $registername—–顯示寄存器registername 的內(nèi)容
不管怎么樣,關(guān)于最后一個錯誤的偽變量是非常有用的:
- $err——–顯示最后一個錯誤的錯誤碼
- $err,hr—顯示最后一個錯誤的錯誤信息
更多閱讀:偽變量
?
技巧3:符合越界后查看堆對象
有時候,在調(diào)試符號越界后,你還想查看對象的值,這個時候,watch窗口中的變量是被禁用的,不能再查看(也不能更新),盡管對象仍然存在。你如果知道對象的地址,可以繼續(xù)充分地觀察它。你可以將地址轉(zhuǎn)換為該對象類型的指針,放在watch窗中。
下面的例子中,當單步跳出do_foo()之后,_foo不能再被訪問。但是,將它的地址轉(zhuǎn)換為foo*后,就可以繼續(xù)觀察這個對象。
?
技巧4:查看數(shù)組的值
如果你在操作一個很大的數(shù)組(我們假設(shè)至少有幾百個元素吧,但是可能更少),在Watch窗口中展開數(shù)組,查找一些特定范圍內(nèi)的元素很麻煩,因為你要不停地滾動.如果數(shù)組是分配在堆上的話,你甚至不能在watch窗口中展開數(shù)組元素.對此,有一個解決辦法。你可以使用(array+ <offset>),<count> 去查看從<offset>位置開始的特定范圍的<count>元素(當然,這兒的數(shù)組是你的實際對象)。如果想查看整個數(shù)組,可以簡單使用array,<count>.
如果你的數(shù)組是在堆上,你可以在watch窗口中將它展開,但是要查看某個特定范圍的值,用法稍有不同:((T*) array + <offset>),<count>(注意這種用法對于堆上的多維數(shù)組也有效)。但是這種情況下,T是指數(shù)組元素的類型。
如果你在用MFC,并使用其中的’array’容器,像 CArray, CDWordArray,CStringArray等等。你當然可以使用同樣的過濾方法。除此之外,你必須查看array的m_pData成員,它是保存數(shù)據(jù)的真實緩存。
?
技巧5:避免進入不必要的函數(shù)
很多時候,你在調(diào)試代碼時可能會進入到你想跳過的函數(shù),像構(gòu)造函數(shù),賦值操作或者其他的。其中最困擾我的是CString構(gòu)造函數(shù)。下面是一個例子,當你準備單步執(zhí)行take_a_string()函數(shù)時,首先進入到CString的構(gòu)造函數(shù)。
| 1 2 3 4 5 6 7 8 | void take_a_string(CString const &text) { } void test_string() { ???take_a_string(_T("sample")); } |
幸運的是可以告訴調(diào)試器去跳過哪些方法,類或者整個命名空間。實現(xiàn)它的方法也已經(jīng)改變了,回到使用VS6的日子,通常是通過autoexp.dat文件來指定的。Vistual Studio 2002改成了使用注冊表設(shè)置。想要跳過一些函數(shù),你需要在注冊表里添加一些值(詳情如下):
為了避免進入任何CString方法,我添加了下面的規(guī)則:
?
有了這個,即使你強制進入上例中的take_a_string(),調(diào)試器也會跳過CString的構(gòu)造函數(shù)。
更多閱讀:
- ?使用Visual C++調(diào)試器怎樣避免進入函數(shù)
- 使用AutoExp.dat調(diào)整調(diào)試器
技巧6:從代碼啟動調(diào)試器?Launch the debugger from code
你可能很少需要將調(diào)試器附加到程序中,但你不能在Attach窗口這樣做(可能因為中斷發(fā)生太快而沒有捕獲到),你也不能一開始就在調(diào)試器中啟動程序。你可以在程序中產(chǎn)生中斷給調(diào)試器一個機會通過調(diào)用內(nèi)部的_degbugbreak()來附加。
| 1 2 3 4 | void break_for_debugging() { ???__debugbreak(); } |
實際上還有其他的方法來完成,例如觸發(fā)中斷3,但這僅僅適用于x86平臺(C++64位不再支持ASM)。另外還有DebugBreak()函數(shù),但它的使用不怎么簡便,所以這里推薦使用內(nèi)部方法。
| 1 | __asm int 3; |
?? 程序運行內(nèi)部方法時會停止運行,這時你就有機會將調(diào)試器附加到該進程。
?
?
?
更多閱讀:
- ?內(nèi)部方法_debugbreak
- 任何時候都離不開設(shè)置斷點和斷言
- Visual Studio 20005/2008的調(diào)試,第四部分:為調(diào)試器設(shè)置代碼
技巧7:在output窗口打印
通過調(diào)用DebugOutputString可以在調(diào)試器的output窗口顯示一段特定的文本。如果沒有附加的調(diào)試器,該函數(shù)什么也不做。
?
更多閱讀:
- 函數(shù)OutputDebugString
- 函數(shù)OutputDebugString的調(diào)用機制
技巧8:隔離內(nèi)存泄漏
內(nèi)存泄漏是在原生開發(fā)中的一個很重要的問題,要檢測內(nèi)存泄漏是一個很嚴峻的挑戰(zhàn),尤其是在大型項目中。Vistual Studio可以提供檢測內(nèi)存泄漏的報告,還有其他的一些應(yīng)用程序(免費的或商業(yè)的)也可以幫助你檢測內(nèi)存泄漏.有些情況下,在一些內(nèi)存分配最終會導(dǎo)致泄漏時,可以使用調(diào)試器去中斷。但是你必須找到可再現(xiàn)的分配編號(盡管沒那么容易)。如果能做到這一點,執(zhí)行程序時調(diào)試器才會中斷。
?我們來看下面的代碼,分配了8個字節(jié),卻一直沒釋放分配的內(nèi)存。Visual Studio提供了造成內(nèi)存泄漏的對象的報告,多運行幾次,會發(fā)現(xiàn)一直是同一個分配編號(341)。
| 1 2 3 4 5 6 7 8 9 | void leak_some_memory() { ???char* buffer = new char[8]; } Dumping objects -> d:\marius\vc++\debuggingdemos\debuggingdemos.cpp(103) : {341} normal block at 0x00F71F38, 8 bytes long. ?Data: <??????? > CD CD CD CD CD CD CD CD Object dump complete. |
在一個特定的(可復(fù)現(xiàn)的)位置中斷的步驟如下:
遵循這些步驟,?在上個例子中,使用分配的編號(341)就可以識別內(nèi)存泄漏的起因。
?
技巧9:調(diào)試發(fā)行版
調(diào)試和發(fā)布是兩個不同的目的。調(diào)試配置是用于開發(fā)的,而發(fā)布配置,顧名思義,是用來作為程序的最終版本,因為它必須嚴格遵循發(fā)布的質(zhì)量要求,該配置包含優(yōu)化部分和調(diào)試版本的中斷調(diào)試的設(shè)置。而且,有時候,要像調(diào)試調(diào)試版本一樣去調(diào)試發(fā)行版。要做到這一點,你需要在配置里做一些改變。但是這種情況下,你就不再是在調(diào)試發(fā)行版,而是調(diào)試和發(fā)行的混合版。
?
你還應(yīng)該做一些事兒,以下是必須要做的:
如圖所示:
?
更多閱讀:怎樣調(diào)試發(fā)行版
技巧10:遠程調(diào)試
另一個重要的調(diào)試就是遠程調(diào)試,這是一個更大的話題,多次被提到,這里我只做一下簡單的概括:
?
?
1)本地的PDB文件必須可用(在遠程機器的相同路徑下放置一個對應(yīng)的模塊)。
?2) 遠程機器上的托管PDB文化必須可用。
遠程調(diào)試監(jiān)控下載:
- ?Visual Studio 2008 Service Pack 1 Remote Debugger
- Microsoft Visual Studio 2010 Remote Debugger
更多閱讀:
- 設(shè)置遠程調(diào)試
- 怎么運行遠程調(diào)試監(jiān)控
- 遠程調(diào)試時加載調(diào)試符號:本地對托管
- PDB文件:開發(fā)者須知
- Visual Studio遠程調(diào)試和PDB文件
- 怎樣指定符號位置和加載行為
結(jié)束語
Ivan Shcherbakov那篇文章和我這篇文章提到的調(diào)試技巧,在大多數(shù)的調(diào)試問題中都是必不可少的。想要知道更多的關(guān)于調(diào)試技巧的知識,建議閱讀文章中提供的額外閱讀。
總結(jié)
以上是生活随笔為你收集整理的Visual Studio原生开发的10个调试技巧的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: PHP 性能分析
- 下一篇: Visual Studio原生开发的20