如何用VS進行程序調試

VS是一個強大的IDE,如果你現在只會簡單地用它查看一下執行效果,那就太大材小用了。

1. CRT函數報錯

首先來說說最常見的一個編譯錯誤。微信裏常常收到這個錯誤的截圖提問。

CRT(C Runtime Library = C運行時間庫)是windows平臺下的一個概念。CRT函數準的C語言函數。例如:printf、scanf、strlen、fopen等函數都屬於CRT函數。

安全CRT函數是微軟對C/C++的擴展,對大部分的CRT函數都派生了一個新的函數形式。比如把fopen函數重新定義如下:

errno_t fopen_s(FILE** pFile, const char *filename, const char *mode);

微軟認爲,使用這種函數能夠幫助開發者更好地規避內存泄露、空指針訪問等常見問題。爲了儘量讓大家養成使用安全CRT的習慣,在編譯沒有使用安全CRT函數的代碼時,VS會報出如下錯誤:

Error 1 error C4996: 'freopen': This function or variable may be unsafe.
Consider using freopen_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS.
See online help for details. e:\c\vstestc\vstestc\fileoper.c 8 1 VSTestC

如果你想讓自己的代碼寫的更通用,不想使用微軟的所謂安全CRT函數,可以使用下面的方法:

1.1 代碼中定義宏

如果你仔細越短報錯信息,就會發現其實VS已經告訴你怎麼解決了。只要定義一下_CRT_SECURE_NO_WARNINGS就能解決。把下面的句子寫在代碼中:

#define _CRT_SECURE_NO_WARNINGS

現在編譯是不是就成功了。

1.2 工程中配置

如果非安全CRT函數用在很多不同的文件中,由於作用域的關係,你可能需要在多處寫下宏定義語句。這樣不太方便,這時候你可以選擇在工程配置中一勞永逸的解決這個問題。步驟如下:

  • 打開工程屬性界面

在工程名上右鍵,選擇“Properties”,進入下面的界面。


  • 宏定義添加窗口

如圖,選擇“Configuration Properties” -> “C/C++” -> “Preprocessor” -> “Preprocessor Definitions”。點擊右邊的下拉箭頭,之後點擊“Edit”。

  • 添加宏定義

_CRT_SECURE_NO_WARNINGS添加到List中。


之後,點擊OK。

現在編譯試試,報錯沒有了。

1.3 靜態引用運行時庫

打開打開工程屬性界面,選擇“C/C++” -> “Code Generation” -> “Runtime Library”。


如圖,默認情況下是動態引用。我們需要改成靜態引用。


下拉窗中的四個選項意義如下。

對與debug版本的程序:

  • /MTd 靜態引用運行時庫的debug版本
  • /MDd 動態引用運行時庫的debug版本

對與release版本的程序:

  • /MT 靜態引用運行時庫的release版本
  • /MD 動態引用運行時庫的release版本

1.4 忽略警告

報錯信息中,有這樣一部分error C4996:,這是這個問題的錯誤碼。我們可以顯示地要求VS不要提示這種問題的信息。只要在代碼開始的部分加入下面這句話即可:

#pragma warning(disable:4996)

問題是不是解決了。


2. 查看運行結果

#include 

int main()
{
    printf("Hello world!");
    return 0;
}

上面這段代碼,如果直接按F5運行,你會看到一個一閃而過的控制檯窗口。這個窗口出現的時間很短,以至於很難看清楚結果。解決這個問題又很多方法,常見的大概有下面四種:

2.1 Ctrl + F5

這個是最常見的方法,按下Ctrl + F5組合鍵,會看到下面這個結果:


美中不足的是系統會自動添加一行字:“請按任意鍵繼續...”。當你按任意鍵之後,窗口消失。

2.2 斷點


如圖所示,在最後一行代碼處打斷點。之後,按F5開始調試執行程序,會看到下面這個結果:


程序被停在斷點處,而命令行窗口也被停下了。看完結果後,只需要再按一下F5繼續執行程序,它就會正常結束。

2.3 getch()

通過getch函數,可以實現和2.1相同的效果,不過沒有哪行字。代碼如下:

int main()
{
    printf("Hello world!");
    getch();
    return 0;
}

執行這段代碼,命令行會停在新加這行代碼執行後,直到按下任意鍵程序才繼續執行到結束。

2.4 system("pause")

system函數是不是很熟悉,上一篇文章中我們已經認識過了。加上這句話其實是調用了系統提供的pause這個命令。效果和2.1完全相同。

3. 單步調試

依然是前面那段代碼,我們按F10鍵來進行單步調試。


左邊黃色的箭頭表示當前程序的執行位置。按一下F10鍵,箭頭指向的這行代碼就被執行,同時箭頭指向下一行。這樣完全按照程序運行的過程執行。


如果程序是這樣,在調用Function函數時,如果按F10,程序會一次執行完整個Function函數。但如果你按F11,箭頭會進入Function函數內部,就像這樣:


在程序運行中,把鼠標停留在一個變量上,此時會看到這個變量當前的值。如下圖:


當然,還可以把這個變量拖入watch窗口,這樣就能實時查看這個變量的變化:


單步調試還有很多神奇之處需要你慢慢發現。這部分內容不好講,不過你只要稍微操作一下就能學會。

4. 條件斷點

int main()
{
    int i;
    for (i = 0; i < 100; i++)
    {
        printf("i = %d\n", i);
    }

    return 0;
}

這段代碼很簡單,打印0~99這100個數,假如,我是說假如你的程序運行到第95次循環時出現了問題,如果你想單步調試看看i的變化情況,你不可能一直按F10直到第95次循環。那樣手肯定吃不消。這時候,就用到了條件斷點的方法。修改代碼如下:


如圖,添加一組 if 語句,把斷點打在 if 中的代碼裏。現在按F5調試執行,程序會在第95次循環中我們打斷點的地方停下,之後你再按F10單步調試就好了。是不是簡單多了。

5. 調試的樂趣

調試代碼能夠讓編程變得不那麼枯燥。當你一步一步跟着程序的執行方式去思考問題,你會更加深刻地體會計算機的某些邏輯。

另外,在你寫程序時,腦子裏想的是如何設計代碼,但在你調試的過程你會在另外一個角度去審慎這段代碼,這時你很容易發現其中的不足之處。很多情況下,一個程序有問題,看代碼怎麼也發現不了究竟錯在哪裏,不過一調試就能馬上找到。

學會了代碼調試,你的編程學習就算是真正入門了。它不僅僅是你軟件開發中的工具,也是編程學習過程中不斷提高和不斷自我完善的神奇。

學習過程中遇到什麼問題或者想獲取學習資源的話,歡迎加入學習交流羣
639368839,我們一起學C/C++!
發佈了61 篇原創文章 · 獲贊 35 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章