一、調試之前要做的工作
首先,我們要確保Code::Blocks的配置正確,調試工作才能進行得更順利
為此,我們需要生成調試符號。調試符號可以讓調試器知道代碼的哪一行正在執行,這樣你就可以知道程序運行到哪里了。
為確保調試符號設置正確,請在Code::Blocks中選擇項目 | 編譯選項(Project | Build Options),會看到這樣一個對話框:

你需要確保調試(Debug)目標里的生成調試符號(Produce debugging symbols)選項被勾選上。
還需要在編譯 | 選擇目標 | 調試(Build | Select Target |Debug)中,確保調試(Debug)作為項目的目標被選中:

以上操作確保了目標是對項目進行調試,調試器將使用調試符號來編譯你的程序。
二、設置斷點
調試器的價值在於,它能讓我們看到程序正在做的事情——哪些代碼正在執行,以及變量的值是多少。
為此,我們在程序的某個地方設置斷點,然后在調試器下運行該程序。調試器將執行程序,直到到達設置了斷點的代碼行。此時,編譯器便可以讓你查看程序,或者一步步地執行程序,檢查代碼的每一行是如何影響你的變量的。
首先我們來看一段用來計算特定數額資金的利率(interest rate)、年利息(compounded annually)的程序:
#include <iostream> using namespace std; double computeInterest (double base_val, double rate, int years) { double final_multiplier; for ( int i = 0; i < years; i++ ) { final_multiplier *= (1 + rate); } return base_val * final_multiplier; } int main () { double base_val; double rate; int years; cout << "Enter a base value: "; cin >> base_val; cout << "Enter an interest rate: "; cin >> rate; cout << "Enter the number of years to compound: "; cin >> years; cout << "After " << years << " you will have " << computeInterest( base_val, rate, years ) << " money" << endl; }

看了運行結果,很明顯,出現了錯誤,這時我們將設置斷點開始進行調試。
1,先在main函數開始的地方,設置一個斷點。這樣就可以查看整個程序的執行過程了。
(1)將光標移到 double base_val 這一行
(2)選擇 調試 | 設置斷點 (Debug | Toggle Breakpoint)或者按下F5。這會在該代碼行旁邊的側邊欄中設置一個小紅點,表明這一行有一個斷點:

(3)可以使用設置斷點命令或者單擊小紅點用來設置或取消設置該斷點。
(4)開始運行程序。選擇調試 | 開始(Debug | Start)或者按下F8。

這樣程序將正常執行,直到遇到斷點。
現在我們應該看到了打開的調試器,它看起來應該是這樣的:

首先要注意的是小圓點下面的三角形,它表示接下來要執行的代碼行。它跟小紅點之間相隔若干行。
它之所以沒有緊挨着小紅點,是因為變量的聲明不產生任何的機器代碼,因此,盡管斷點看起來是在15行,但實際上它在第18行。
(5)這時應該還有一個監視(Watches)窗口打開了,如下圖:

我已經展開了監視窗口的兩個子項:局部變量(Local variables)和函數參數(Function Arguments)。
監視窗口會顯示出所有當前可用的變量,包括局部變量和函數參數,以及這些變量的值。
注意:這里看起來像亂碼的原因是因為我們還沒有對它們進行初始化,這也是接下來的幾行程序所要做的事情。
(6)為了執行接下來的幾行代碼,我們需要告訴調試器向下執行下一行(F7)。
所謂向下執行一行,就會執行當前的代碼行,也就是三角形所標識的那一行。

一旦走到下一行,程序就會執行cout語句,輸出一條信息到屏幕中,要求你輸入一個值。
如果你嘗試輸入一個值但沒有任何效果——因為程序還在調試器的控制之下。
再次按下F7后,程序會等待用戶輸入,因為這時候cin函數還未返回——cin函數需要在返回前得到用戶的輸入。
重復這一過程,分別輸入0.1給利率,輸入1給年數。
現在,斷點到達了這一行代碼:

再次確認輸入是否正確。我們可以通過監視窗口來檢查局部變量的值:

注意:rate的值不是0.1,是因為0.10000...1中最末尾的1只是浮點數的一種怪異的表達方式(浮點數並不是精確的),它實在太小了,對大多數程序來說不會造成很大影響。
(7)現在我們確定一切都沒問題,來調查一下computerInterest函數中會發生什么,單步執行(Step into)。

單步執行會進入當前行的函數里面去執行,而不像下一行命令,只是執行函數然后顯示給你最終的結果。
現在我們就單步進入computerInterest函數之中:

(8)從結果中我們可以看出函數的參數部分一切正常,但變量i 和 final_multiplier 值不對勁。
為此,使用下一行命令(F7),執行循環語句,由於它與一些初始化操作相關聯,我們看看會發生什么。

(9)從中我們可以看出,final_multiplier沒有正確初始化。而且,接下來要執行的語句將要用到final_multiplier:
final_multiplier *= (1 + rate);
這條語句的意思是,將final_multiplier乘以(1+rate),再把結果重新賦值給final_multiplier。但是我們看到final_multiplier並沒有被初始化,因此這個乘法的結果也將會是一個莫名其妙的值。
(10)如何修復bug?
我們需要在聲明final_multiplier變量的語句中,把它也初始化。在這個例子中,它應該被初始化1。
double final_multiplier=1;
(11)修復bug后的運行結果為:

三、總結
通過以上一個簡單的程序案例,使我掌握了調試一個程序的基本流程,和分析bug的過程,為以后自己獨立尋找bug,解決bug提供了實用的技能。
我不光可以寫bug,還能Debug!
