1. 程式人生 > 實用技巧 >繼續分享 5 個實用的 vs 除錯技巧

繼續分享 5 個實用的 vs 除錯技巧

繼續分享 5 個實用的 vs 除錯技巧

總結除錯vs2019vs

前言

我在上一篇文章《5 個非常實用的 vs 除錯技巧》 中分享了 5 個我認為非常值得了解的 vs 除錯技巧,本週繼續分享 5 個很基礎但同樣實用的除錯技巧。

1. 條件斷點

作用簡介:

顧名思義,帶條件的斷點。滿足條件才中斷。條件斷點非常非常有用,使用得當,可以極大縮短我們除錯問題的時間。比如,有一個大迴圈,只在第 1024 次迴圈的時候有問題,我們如果單步(在 vs 中可以按 F10),恐怕手得按殘了。又比如,我們想在特定條件下中斷。這時候條件斷點就是我們的救星。

2. 記憶體斷點

作用簡介:

顧名思義,針對記憶體設定的斷點。對於除錯邏輯復(hun)雜(luan)的程式,非常非常有用。比如,有一個全域性變數的值,在程式碼中有 N

個地方會改動它,在除錯程式的時候,不知道這個全域性變數在哪裡被改變了,如果能在改動的那一刻中斷下來該有多好啊!這可是記憶體斷點的專長!


memoryaccess-breakpoint

開啟方式:

除錯的時候,通過 除錯 -> 視窗 -> 斷點 即可開啟斷點視窗。在 vs2013 中對應的快捷鍵是 ctrl + alt + b 。開啟後可以 通過 新建 -> 新建資料訪問斷點(D)... 建立一個數據訪問斷點。

注意:

  1. 只有在程式中斷到偵錯程式的時候才允許新建資料訪問斷點。

  2. 輸入的是記憶體地址,可以直接輸入地址值,也可以通過 & 獲取地址。

  3. vs

    中好像只支援指定的記憶體範圍的值發生變化時才中斷。windbg 中的 ba 命令更強大,感興趣的小夥伴兒可以檢視 windbg 的幫助文件。

3. 異常開關

作用簡介:

異常最多分發兩輪,每輪都會優先分發給偵錯程式。如果偵錯程式沒處理,會繼續分發給異常處理函式。具體的分發過程可以參考《軟體除錯》。

比如,在下面的示例程式碼中。我在 ExceptionDemo() 中加上了 try {} catch {} 來捕獲一些異常。在 FunctionE() 中的某一行設定好斷點,如果一切正常是可以斷下來的。但是在 FunctionD() 中有可能丟擲異常,如果根據設定,vs 不處理這個異常,該異常會被 ExceptionDemo()

處理,還沒執行到設定斷點的地方就被異常改變了執行流程。

#include "stdafx.h"
#include <exception>

bool application_quit = false;
int g_runningLoop = 0;

void FunctionA();
void FunctionB();
void FunctionC();
void FunctionD();
void FunctionE();

void ExceptionDemo()
{
    try
    {
        while (!application_quit)
        {
            FunctionA();
        }
    }
    catch (std::exception)
    {
    }
}

void FunctionA() { FunctionB(); }
void FunctionB() { FunctionC(); }
void FunctionC() { FunctionD(); }
void FunctionD()
{
    if (++g_runningLoop > 6)
    {
        throw std::exception("too many loops!");
    }
    FunctionE();
}

void FunctionE()
{
    if (g_runningLoop > 10)
    {
        application_quit = true;
    }
}


exception

p.s. 雖然在程式碼中增加 try {} catch {} 有助於提高程式的健壯性,但有時候可能不利於我們發現問題,有些問題可能就被“默默”吞掉了。

開啟方式:

除錯的時候,通過 除錯 -> 異常(X)... 即可開啟異常設定對話方塊。在 vs2013 中對應的快捷鍵是 Ctrl + Alt + E

**注意:**只有在除錯的時候才能設定,不除錯的時候是看不到異常設定選單的。

4. 除錯時修改值

作用簡介:

假設我們正在除錯如下程式碼,跟蹤到了 if (bRich) 這一行,期待的 bRich 的值是 true,而實際值是 false。我們可以手動修改 bRich 的值為 true 來強行進入 if 分支,而不是 else 分支。(BTW,改完就真的有錢了麼?)

#include "stdafx.h"
#include <iostream>

bool HaveIMakeEnoughMoney()
{
    return false;
}

void ManualModifyValueDemo()
{
    auto bRich = HaveIMakeEnoughMoney();
    if (bRich)
    {
        std::cout << "Finally, I'm rich!" << std::endl;
    }
    else
    {
        std::cout << "Oops, I'm still poor!" << std::endl;
    }

}


manual-modify-variable

小貼士:不僅可以通過懸浮視窗改變變數的值,我們還可以通過監視視窗記憶體視窗等其它方式改變變數的值。

5. 拖動到指定位置執行

作用簡介:

相信,大家都有過手滑的情況,本來想的是單步步入(在 vs 中按 F11)特定函式,沒想到卻按成了 F10,華麗麗的錯過了想除錯的函式,這時候我們可以拖回來。又或者如上面的程式碼,當執行到第24行的時候,發現 totalMoney 的值不是我們想要的,我們想重新回到前面跟蹤一下totalMoney 的值是怎麼來的,而我們又不想重新走一遍整個流程(因為可能很慢)。這時候我們可以手動拖動黃色小箭頭到第 22 行。請看下圖:


drag-to-specific-line

注意:

拖動功能是通過設定 eip(rip) 的值來實現的,拖動需謹慎,有些情況下可能導致程式崩潰!

測試工程下載地址

百度雲盤 連結: https://pan.baidu.com/s/1MSjUNPF-JHoY1t3l1xXFeg 提取碼: jew2

CSDN:https://download.csdn.net/download/xiaoyanilw/12640122

總結

本次介紹的 5 個除錯技巧雖然都很基礎,但是卻非常實用,而且使用頻率比較高。不知道你是否有所收穫呢?

參考資料

《軟體除錯》