dev C++ 4.9.9.2

原始程式碼除錯器

前言

整合程式開發環境 (Integrated Development Environment, IDE, 例如 Visual Studio, Borland C++, Dev C++, Turbo C 等等) 環境中原始程式碼除錯器 (Source Code Debugger) 是一個很好用的工具, 正確使用的情況下你可以很快地能夠看到程式執行時的錯誤,很快地找到你的程式中可能有錯誤的地方,尤其是對於電腦系統工程師來說, 必須和很多別人寫的程式一起工作, 遇見記憶體存取相關的錯誤時這個工具更是不可或缺。

在初學時很多同學也會覺得它一列一列顯示程式的動作, 可以讓你了解你自己寫的敘述究竟CPU是如何執行的,對於所學到的新語法能夠更有體會。

不過這個工具對初學者不是沒有缺點的, 有時太依賴這樣的工具來偵錯, 使得製作程式的過程變成

  1. 先寫出一個大概的程式或是把可能可以用的程式集合在一起
  2. 先編譯成功後, 慢慢用除錯器去更正裡頭的錯誤

如此的程式變成用 "拼湊" 起來的了, 最常看到的現象是好不容易更正出希望要的答案出來以後, "所使用的語法與邏輯到底是哪裡出錯了, 哪些語法和你腦中認知的不太一樣" 卻忘記了...如此辛辛苦苦除錯完畢, 但是卻常常沒有得到l練習設計的效果。

另外透過除錯器偵錯的過程裡, 常常只需要看到局部的邏輯, 反正可以直接看到資料的數值, 就可以省掉預測你的程式會如何處理資料的這一個步驟, 你對於程式敘述的掌握能力也就會建立不起來。

所以這也是我們一直沒有急著告訴大家原始程式碼除錯器該如何使用的原因。

以下我們由最開始簡單介紹 dev C++ 4.9.9.2 原始程式碼除錯器的基本功能。

dev C++ 4.9.9.2 的除錯器是基於 GNU gdb 作出來的免費軟體, 在功能上其實比起商用的軟體, 例如 M$ 的 Visual Studio, 有一些差距, 不要太苛求。

另外當 dev C++ 執行程式遇見程式的記憶體存取錯誤 (segmentation fault) 時, 就出現下面的視窗

作業系統希望執行 Just-in-Time 原始碼除錯, 但是目前只有 Visual Studio 2008 的選項, 你可以由 Visual Studio / 工具 / 選項 / 偵錯 / Just-in-Time 把所有的都取消, 但是 dev c++ 好像沒有提供 Just-in-Time 偵錯, 所以你還是得關掉視窗, 只知道程式執行時發生嚴重的記憶體存取錯誤, 卻不知道是執行哪一段程式時發生的。如果你用 Visual Studio 的話, 就可以很快地在 JIT 除錯器中看到程式執行到哪裡發生這個錯誤

建立新原始碼

這裡我們盡量簡化, 如果你新增一個專案, 然後在裡面加入新的原始碼也是可以的

拷貝下列程式進入編輯區域, 存檔為 testDebug.c

 

程式內容如下

#include <stdio.h>
#include <stdlib.h>

double square(double x);

int main(void)
{
    double data, result;
    int i;

    printf("請輸入正方形的邊長:");
    scanf("%lf", &data);

    result = square(data);

    printf("邊長 %f 的正方形, 面積是 %f\n", data, result);

    for (i=0; i<5; i++)
    {
        result = result / 2;
        printf("%d %f\n", i, result);
    }

    system("pause");
    return 0;
}

double square(double x)
{
    double sq;
    sq = x * x;
    return sq;
}
上面這個程式有用到自己定義的函式 square() 還有迴圈 for ..., 雖然在課堂裡都還沒有講到, 但是這裡你有編譯器還有除錯器, 等一下藉由除錯器一步一步的動作, 你應該可以很快看出來它們在程式裡的作用, 以下我們先編譯執行一下程式 :

編譯程式 (快速鍵 Ctrl+F9)

編譯結果如下

編譯成功後可以直接執行程式 (快速鍵 Ctrl+F10)

顯示下列執行視窗, 輸入資料 123 並顯示結果

接下來我們要說明 原始程式碼除錯器 的基本用法

原始程式碼除錯器最主要兩個功能是

  1. 顯示程式執行過程中每一個變數裡資料的變化
  2. 顯示程式敘述的執行順序

我們以剛才這個 testDebug.c 程式為例

首先在可能有錯誤的地方以滑鼠左鍵點選該列前方設定中斷點

開始偵錯 (快速鍵 F8)

或是在工具列上按除錯按鈕

原始程式碼除錯器 停在第一個中斷點之前, 藍色列代表目前正準備執行的程式敘述

左邊自動跳到 "除錯/監看" 視窗, 以便觀察目前區域變數裡存放的數值或是任何 "監看式" 的數值, 目前我們都還沒有設定所以是空白的

下方也跳到 "除錯/監看" 控制面板, 顯示在除錯時會用到的一些快速控制按鈕

另外也出現執行程式的視窗, 目前因為還沒執行 printf 所以是空的

請按單步執行 (F7), 藍色列以及前面的藍色箭頭移到 scanf, 執行視窗中也顯示 printf 的列印結果

目前準備執行的是呼叫 scanf() 函數, 我們打算在 "除錯/監看" 視窗 中觀察程式的執行過程和每一個敘述的作用, 所以我們來設定一些要監看的變數和監看式

最簡單的方法是把滑鼠移到想要看的變數上方, 例如下圖中的 data, 稍微等後一下, 左邊視窗裡就會出現 data = ... 的顯示, 由於 scanf 函數還沒有執行, 所以 data 變數裡的資料是先前執行其他程式時記憶體裡殘存的數值, 對這個程式而言沒有太大意義

你也嘗試把變數 result 和變數 i 都加進來, 然後你可以按下方的新增監看式 (F4), 出現下面視窗, 輸入 i<5

如此就可以在 "除錯/監看" 視窗裡看到如下畫面

i < 5 是迴圈執行時測試是否要繼續的條件敘述, 當你輸入為監看式的時候, 除錯器根據程式執行時變數 i 的數值來計算 i < 5 的數值, 目前 i 是 20 (其它程式執行後殘留在記憶體裡的數值), 計算的結果 i 並不小於 5, 所以數值為 0 (代表邏輯敘述為偽), 如果小於 5 的話, 數值為 1(代表邏輯敘述為真)

接下來就請你按 "單步執行 (F7)" 並且在執行視窗內輸入數字, 例如 123.4

請注意每一步到底執行了哪一列以及觀察變數裡的資料變化

此時藍色箭頭往下移動到下一列 result = square(data);, 準備呼叫 square() 函數, 函數執行完以後的結果會設定在 result 變數中

此時請點選 "追蹤入函式 (Shift-F7)", 於是程式暫停在第 31 列, square() 函式的第一列, 請將變數 x 加入監看視窗, 請注意此時參數 x 的資料已經是 123.4 了

我們可以點選下方的 "反向追蹤" 面板, 顯示函式呼叫的順序

這裡告訴你 main() 函式執行到第 14 列, 呼叫 square() 函式, square 函式目前執行到第 31 列

你可以用滑鼠點選這兩列, 編輯視窗裡會直接顯示那列的內容 (如果你的程式有 300 列, 這樣可以很快地看到那一列的程式)

接下來請你按 "單步執行 (F7)", 並觀察變數 sq 裡面資料的變動

接下來請你按 "單步執行 (F7)" 一直到 return() 執行完畢, 回到呼叫端後停在下一列程式 (第 16 列), 這時候也請你注意 square() 執行完以後, 還有一個 result = 的動作, 做完以後當然 result 變數的內容就變了

如果你覺得 "除錯/監看" 視窗 裡有一些資料是你不再需要的, 你可以用滑鼠左鍵點選它, 然後按 Delete

接下來請你按 "單步執行 (F7)" 執行 printf 函數, 在執行視窗裡顯示下列資料

接下來請你按 "單步執行 (F7)" 進入 for 迴圈, 此時請特別注意左方變數 i 的內容, 還有監看式 i<5 的數值, 以及變數 result 的數值

任何時候如果你不想除錯了, 可以按"中斷執行 (Ctrl-Alt-F2)" 來結束偵錯

程式設計課程 首頁

製作日期: 09/16/2012 by 丁培毅 (Pei-yih Ting)
E-mail: pyting@mail.ntou.edu.tw TEL: 02 24622192x6615
海洋大學 電機資訊學院 資訊工程學系 Lagoon