VS下如何調試程序

程序崩潰的原因分類

  1. 函數棧溢出 
    一個變量未初化、未賦值,就讀取它的值。 
    ( 這屬於邏輯問題,往往是粗心大意的導致的 )
  2. 函數棧溢出 
    (1)定義了一個體積太大的局部變量 
    (2)函數嵌套調用,層次過深(如無窮遞歸)
  3. 數組越界訪問 
    訪問數組元素時,下標越界
  4. 指針的目標對象不可用 
    (1)空指針 
    (2)野指針 
    • 指針未賦值
    • free/delete釋放了的對象
    • 不恰當的指針強制轉換


1 導言

在軟件開發週期中,測試和修正缺陷(defect,defect與bug的區別:Bug是缺陷的一種表現形式,而一個缺陷是可以引起多種Bug的)的時間遠多於寫代碼的時間。通常,debug是指發現缺陷並改正的過程。修正缺陷緊隨debug之後,或者說二者是相關的。如果代碼中存在缺陷,我們首先要識別造成缺陷的根本原因(root cause),這個過程就稱作調試(debugging)。找到根本原因後,就可以修正缺陷。

那麼如何調試代碼呢?Visual Studio提供了很多用於調試的工具。有時調試需要花費大量時間去識別root cause。VS提供了許多輔助調試的便捷的工具。調試器(Debugger)包含錯誤列表、添加斷點、可視化的程序流程、控制執行流程、Data Tips、監視窗口(watch windows)、多線程調試、線程窗口、並行調試概覽以及IntelliTrace調試概覽。我希望本文能夠對調試功能的使用者有所裨益。請注意,本文使用VS2010。某些功能在舊版本中也是一致的,但是VS2010新增了許多features(Labeling breakpoint, Pinned DataTip, Multithreaded Debugging, Parallel debugging and IntelliTrace)。

2 如何啓動調試?

可以通過VS的調試(Debug)菜單啓動調試。點擊調試菜單下的“啓動調試”或者按F5鍵啓動。如果你已經在代碼中加入了斷點,那麼執行會自動開始。


圖 啓動調試(Start Debugging)

“附加到進程(Attach to Process)”是另一種啓動調試的方法。Attach Process會爲應用程序啓動一個調試會話。可能我們更熟悉ASP.NET Web應用的Attach Process調試。我發了另外兩篇相關的帖子。如下:

通常我們通過在可能存在問題代碼處加斷點來啓動調試。因此,我們從斷點開始講起。

3 斷點(Breakpoints)

斷點用於通知調試器何時何處暫停程序的執行。通過點擊左邊欄或者按F9鍵在當前行添加斷點。在加斷點之前,你需要知道你的代碼將會出現什麼錯誤,在什麼地方停止執行。當調試器執行到斷點處時,你可以使用其他的調試工具覈對代碼何處出現錯誤。


圖 設置斷點(Set Breakpoint)

3.1 使用斷點進行調試

你已經在你想要暫停執行的地方設置了斷點。現在按F5鍵啓動調試,當程序執行到斷點處時,自動暫停執行。此時你有多種方式來檢查代碼。命中斷點(hit the breakpoint)後,加斷點的行變爲黃色,意指下一步將執行此行。

在中斷模式下,你有多條可使用的命令,使用相應命令進行進一步的調試。


圖 斷點工具條(Breakpoint Toolbar)

3.1.1 逐過程(Step Over)

調試器執行到斷點後,你可能需要一條一條的執行代碼。”Step Over“[F10]命令用於一條一條的執行代碼。這將執行當前高亮的行,然後暫停。如果在一條方法調用語句高亮時按F10,執行會停在調用語句的下一條語句上。Step Over會一次整個方法。
debug51
圖: 逐過程(Step Over - F10)

3.1.2 逐語句(Step Into)

它與Step Over相似。唯一的不同是,如果當前高亮語句是方法調用,調試器會進入方法內部。快捷鍵是”F11“
debug52
圖: 逐語句(Step Into - F11)

3.1.3 跳出(Step Out)

當你在一個方法內部調試時會用到它。如果你在當前方法內按Shift - F11,調試器會完成此方法的執行,之後在調用此方法的語句的下一條語句處暫停。

3.1.4 繼續(Continue)

它像是重新執行你的程序。它會繼續程序的執行直到遇到下一個斷點。快捷鍵是”F5“

3.1.5 設置下一語句(Set Next Statement)

這是一個非常有趣的特性。設置下一語句允許你在調試的時候改變程序的執行路徑。如果你的程序在某一行處暫停而且你想改變執行路徑,跳到指定行,在這一行上右擊,在右擊菜單中選擇”設置下一語句“。這樣程序就會轉到哪一行執行而不執行先前的代碼。這在如下情況中非常有用:當你發現代碼中某些行可能會導致程序的中斷(break)而你不想讓程序在那個時候中斷。快捷鍵是Ctrl + Shift + F10
debug3_small
圖: 設置下一語句(Set Next Statement)

3.1.6 顯示下一語句(Show Next Statement [Ctrl+*])

這一行用黃色箭頭標記。這行是程序繼續執行時下一條將執行的語句。

3.2 斷點標籤(Labeling in Break Point)

這是VS2010提供的新特徵(feature)。用於更好的管理斷點。它使得我們能夠更好的分組和過濾斷點。這像是對斷點的歸類。如果我們添加了與某一功能相關的不同類型的斷點,我們可以根據需要使能(enable)、取消(disable)、過濾(filter)這些斷點。例如,假設我們要調試一下代碼塊。
[csharp] view plain copy
  1. class Program  
  2.     {  
  3.         static void Main(string[] args)  
  4.         {  
  5.             string[] strNames = { "Name1""Name2""Name3""Name4""Name5""Name6" };  
  6.   
  7.             foreach (string name in strNames)  
  8.             {  
  9.                 Console.WriteLine(name);   // BreakPoint  
  10.             }  
  11.             int temp = 4;  
  12.             for (int i = 1; i <= 10; i++)  
  13.             {  
  14.                 if (i > 6)  
  15.                     temp = 5;  
  16.             }  
  17.         }  
  18.   
  19.         public static void Method1()  
  20.         {  
  21.             Console.WriteLine("Break Point in Method1");   // BreakPoint  
  22.         }  
  23.   
  24.         public static void Method2()  
  25.         {  
  26.             Console.WriteLine("Break Point in Method2");  // BreakPoint  
  27.             Console.WriteLine("Break Point in Method2");  // BreakPoint  
  28.         }  
  29.   
  30.         public static void Method3()  
  31.         {  
  32.             Console.WriteLine("Break Point in Method3");  // Breakpoint  
  33.         }  
  34.     }  
執行程序將停在第一個斷點處。下圖給出了斷點列表。
debug11_small.png
圖: 斷點列表
上圖中Labels列都爲空。下面介紹如何給斷點設置標籤(label)以及如何使用標籤。只需在特定代碼行的斷點符號上右擊(①)或者在斷點窗口中設置(②)即可對任何斷點設置標籤。
debug12_small
圖: 設置斷點標籤(Setting Breakpoint Label)
右擊斷點,點擊編輯標籤(Edit Labels),即可對任意斷點添加標籤。對於示例代碼,我爲所有斷點的標籤起了易於理解的名字。
debug13
圖: 添加斷點標籤(Adding Breakpoint Label)
這些標籤如何輔助我們調試呢?現在,所有斷點都是使能的(enabled)。如果你不想調試method2,一般情況下你必須去對應的方法中一個一個的取消斷點,但這裏你可以通過標籤名過濾或者搜索它們,然後選中它們以方便的取消它們。
debug14_small
圖: 使用標籤過濾斷點(Filter Breakpoint Using Labels)
斷點標籤到此介紹完畢。我舉的例子非常簡單,但是斷點標籤在你調試大量代碼,多個工程等情況下非常有用。

3.3 條件斷點(Conditional Breakpoint)

假設你在多次迭代(循環)處理數據而你只想調試其中某幾次迭代。這意味着你想根據某些特定條件暫停你的程序。Visual Studio斷點允許你設置條件斷點。當且僅當條件滿足時,調試器纔會停住。
首先,你需要在你想暫停執行處設置斷點。然後右擊紅色的斷點圖標。右鍵菜單中點擊”條件“。
debug5_small
圖: 設置斷點條件(Set Breakpoint Condition)
點擊右鍵菜單中的”條件“後,會彈出下面的對話框設置斷點的條件。
debug6
圖: 斷點條件設置
假設你要調試下面的代碼塊:
[csharp] view plain copy
  1. class Program  
  2.     {  
  3.         static void Main(string[] args)  
  4.         {  
  5.          string [] strNames = { "Name1","Name2""Name3""Name4""Name5""Name6"};  
  6.   
  7.             foreach(string name in strNames)  
  8.             {  
  9.                  Console.WriteLine(name); // Breakpoint is here  
  10.             }  
  11.         }  
  12.     }  
你在Console.WriteLine()語句處設置了斷點。當執行程序時,每次for-each循環都會停住。如果你想讓代碼只在name="Name3"時停住,該怎麼辦呢?非常簡單,你只需使用條件name.Equals("Name3")。
debug7
圖: 設置斷點條件
查看斷點符號。它應該看上去像是一個加(+)號在斷點符號內部,這表示該斷點是條件斷點。
debug9
圖: 條件斷點符號(Conditional Breakpoint Symbol)
設置斷點的條件之後,在調試程序,調試器只會在滿足給定條件時才停住。
debug10
圖: 條件斷點命中(Conditional Breakpoint hit)
條件輸入框的自動補全(intellisense):上面給出的斷點條件非常簡單,可以非常容易的寫到條件文本框中。有時你可能需要定義很大很複雜的條件。不必擔心,VS爲條件文本輸入框也提供了自動補全功能。因此,在條件框中輸入就像是在編輯器中一樣方便。如下圖。
debug8_small
圖: 條件文本框的自動補全(intellisense in condition textbox)
我幾乎講解了條件斷點的所有內容。除了下面這點。在條件窗口中有兩個選項:
  1. Is True
  2. Has Changed
我們已經看到”Is True“選項的用途了。”Has Changed“用在當你想在某些值變爲某些特定值的時候停住。

3.4 導入/導出斷點(Import / Export Breakpoint)

3.5 斷點命中計數(Breakpoint Hit Count)

3.6 Breakpoint When Hit

3.7 斷點篩選器(Breakpoint Filter)

你可以限制斷點只對特定進程或線程有效。這在進行多線程程序的調試時非常有用。右擊斷點選”篩選器“即可打開篩選器窗口。
debug40
圖: 斷點篩選器(Breakpoint Filter)
在篩選規則中,你可以設置進程名,進程Id,機器名,線程ID等。我會在多線程調試小節中詳述其用法。

4 數據便籤(Data Tip)

數據便籤是應用程序調試期間用於查看對象和變量的一種高級便籤消息。當調試器執行到斷點時,將鼠標移到對象或者變量上方時,你會看到它們的當前值。你甚至可以看到一些複雜對象(如dataset,datatable等等)的細節。數據便籤左上角有一個“+”號用於展開它的子對象或者值。
debug20
圖: 調試時的數據便籤(DataTips During Debugging)
幾個月前,我發過一篇關於VS 2010 DataTip Debugging Tips的文章。
下面是一些在調試時有用的特性。

4.1 Pin Inspect Value During Debugging

4.2 Drag-Drop Pin Data Tip

4.3 Adding Comments

4.4 Last Session Debugging Value

4.5 Import Export Data Tips

4.6 Change Value Using Data Tips

4.7 Clear Data Tips

5 監視窗口(Watch Windows)

5.1 局部變量(Locals)

列出當前方法中的所有變量。當調試器停在某特定斷點並打開Autos窗口時,將展示當前範圍中與此值相關的變量。
debug30_small
圖:Local Variables

5.2 自動窗口(Autos)

這些變量由VS調試器在調試的時候自動檢測。VS檢測與當前語句相關的對象或變量,基於此列出Autos變量。Autos Variable的快捷鍵是Ctrl + D + A。
debug31_small
圖:Autos - Ctrl + D, A

5.3 監視(Watch)

Watch窗口用於添加變量。你可以添加任意多個變量。添加方法是,右擊變量並選擇“Add to Watch”。
debug32_small
圖:Watch - Ctrl + D, W
也可以使用拖放(Drag and Drop)將變量添加到監視窗口中。從監視窗口中刪除變量的方法是,右擊變量並選擇“Delete Watch”。通過調試窗口,也可以在運行時編輯這些變量值。

有4個可同時使用的監視窗口。
debug33_small
圖:多個監視窗口

若果變量中含有對象實例,左邊會有一個“+”號用於查看對象的屬性和成員。
debug34_small
圖:展開監視變量

5.3.1 Creating Object ID

Visual Studio調試器提供另外一個強大的功能,支持我們爲對象的任何一個特定實例創建一個對象ID(object ID)。這可以用於在任何時間監控任意對象,甚至是該對象位於範圍(scope)之外。在監視窗口(watch window)右擊特定對象變量,再單擊“Make Object ID”即可創建Object ID。
debug35_small
圖: 創建Object ID
在對特定對象變量創建Object ID之後,Visual Studio會給這個對象添加一個數碼和“#”號,用來表示。
debug36_small
圖:添加Object ID後

5.4 

6 即時窗口(Immediate Window)

即時窗口是開發人員常用的功能。它可以在不改變當前調試步驟的情況下修改變量值或者執行一些語句。我們可以通過菜單調試 > 窗口 > 即時(Debug > Window > Immediate Window)打開即時窗口。即時窗口支持一組命令,可在調試的任何時刻執行。它也支持Intellisense。在調試期間,我們可以在即時窗口中執行任何命令或者代碼語句。
debug37
圖:基本即時窗口(Basic Immediate Window)
這是對所有開發人員來說最爲常用的特性,因此我就不一一介紹即時窗口的每一條命令了。

7 調用堆棧(Call Stack)

8 調試多線程程序(Debugging Multithreaded Program)

8.1 Exploring Threads Window

8.2 Flag Just My Code

8.3 Break Point Filter - Multithread Debugging

9 調試並行程序(Debugging Parallel Program)

9.1 Parallel Task and Parallel Stacks

10 Debugging with IntelliTrace

10.1 Overview

10.2 Mapping with IntelliTrace

10.3 Filter IntelliTrace Data

11 調試常用快捷鍵(Useful Shortcut Keys For VS Debugging)

Shortcut KeysDescriptions
Ctrl-Alt-V, ADisplays the Auto window
Ctrl-Alt-BDisplays the Breakpoints dialog
Ctrl-Alt-CDisplays the Call Stack
Ctrl-Shift-F9Clears all of the breakpoints in the project
Ctrl-F9Enables or disables the breakpoint on the current line of code
Ctrl-Alt-EDisplays the Exceptions dialog
Ctrl-Alt-IDisplays the Immediate window
Ctrl-Alt-V, LDisplays the Locals window
Ctrl-Alt-QDisplays the Quick Watch dialog
Ctrl-Shift-F5Terminates the current debugging session, rebuilds if necessary, and starts a new debugging session.
Ctrl-F10Starts or resumes execution of your code and then halts execution when it reaches the selected statement.
Ctrl-Shift-F10Sets the execution point to the line of code you choose
Alt-NUM *Highlights the next statement
F5If not currently debugging, this runs the startup project or projects and attaches the debugger.
Ctrl-F5Runs the code without invoking the debugger
F11Step Into
Shift-F11Executes the remaining lines out from procedure
F10Executes the next line of code but does not step into any function calls
Shift-F5Available in break and run modes, this terminates the debugging session
Ctrl-Alt-HDisplays the Threads window to view all of the threads for the current process
F9Sets or removes a breakpoint at the current line
Ctrl-Alt-W, 1Displays the Watch 1 window to view the values of variables or watch expressions
Ctrl-Alt-PDisplays the Processes dialog, which allows you to attach or detach the debugger to one or more running processes
Ctrl-D,VIntelliTrace Event
到此本文結束。希望你喜歡本文。請分享你的反饋和建議。

12 深入學習(Further Study)

13 總結(Summary)

本文介紹了調試過程的基本內容。介紹瞭如何使用VS調試一個應用程序。我解釋了幾乎所有重要的工具以及它們的使用方法。對於並行程序調試,我只講了基礎部分。在深入學習小節中,深入講解了並行調試過程。如果你感興趣,請閱讀。我的主要目的是涵蓋Visual Studio中提供的幾乎所有調試工具。希望你從本文中學到了一些新知識。

“自動窗口”(Autos):當前使用的變量

“局部窗口”(Locals):在範圍內的所有變量

“監視N”(Watch):可定製(N從1到4)


Step Into(逐語句):執行並移動到下一條語句(實際上,跳入上一條語句的代碼塊,此代碼塊的第一條)

Step Over(逐過程):執行並跳到下一條語句,但不進入上一條語句的代碼塊

Step Out(跳出):執行到代碼塊結尾


命令窗口(Command)

即時窗口(Immediate):主要用於計算表達式


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章