前言
調試是程式設計師最核心的基本功,其重要性甚至超越程式語言本身。不會調試意味著無法編寫可靠軟體。本文系統整理 VC++ 6.0 調試器核心功能:斷點類型、變數觀察、記憶體檢視、呼叫堆疊、進程控制、輔助巨集與工程配置最佳實踐。
專案配置:啟用調試資訊
Alt+F7 開啟 Project Settings:
| 頁籤 | 設定項 | 推薦值 | 說明 |
| C/C++ → General | Debug Info | Program Database for Edit and Continue (/ZI) | 支援編輯後續續執行,含完整型別/符號資訊 |
| Link | Generate Debug Info | ☑ 勾選 | 將調試資訊寫入 EXE/DLL |
| C/C++ → Precompiled Headers | Use Precompiled Header | ☑ 勾選 | 加速編譯,.cpp 首行必須 #include "stdafx.h" |
| C/C++ → Precompiled Headers (針對 .c 檔) | Precompiled Header | Not Using | .c 檔無法使用 stdafx.h |
斷點完整分類與操作
基本斷點
- 設定/切換:游標置於行 → F9
- 管理視窗:Ctrl+B 或 Alt+F9 開啟 Breakpoints 對話框
- 指定位置:Break at → Line xxx / Function / Address
條件斷點
- Breakpoints 對話框 → Condition → 輸入運算式 (如
i == 100)
- 「值改變時中斷」:觀察變數/記憶體區域變化
- 「命中計數」:忽略前 N 次命中,第 N+1 次中斷
資料斷點
- Breakpoints → Data 頁 → 輸入運算式 (如
g_bFlag)
- 當該運算式值發生變化時中斷 (需全域/靜態變數)
訊息斷點
- Breakpoints → Messages 頁
- 輸入視窗處理函數名 → 該函數被呼叫時中斷
- 選擇特定 Windows 訊息 (如
WM_PAINT) → 訊息到達時中斷
變數觀察與檢視工具
| 工具 | 啟動方式 | 功能 | 注意事項 |
| Quick Watch | 變數上右鍵 → Quick Watch | 即時檢視單一變數/運算式值 | 模態對話框,需手動關閉 |
| Watch 1~4 | Debug 工具列 Watch 按鈕 | 持續監視多個變數/運算式 | 運算式不可有副作用 (禁用 ++、= 等) |
| Memory | Debug 工具列 Memory 按鈕 | 檢視指定位址記憶體內容 | 適用陣列、結構體、指標指向區域 |
| Variables | Debug 工具列 Variables 按鈕 | 列出當前作用域所有可見變數 | 當前指令涉及變數以紅色標示 |
| Registers | Debug 工具列 Registers 按鈕 | 檢視 CPU 暫存器值 | 底層除錯專用 |
進程控制鍵盤捷徑
| 按鍵 | 動作 | 說明 |
| F5 | 繼續執行 | 運行至下一個斷點或程式結束 |
| F10 | 單步跳過 | 不進入函數內部 |
| F11 | 單步進入 | 進入函數內部 |
| Ctrl+F10 | 執行至游標處 | 快速跳過已知無誤代碼段 |
呼叫堆疊
- Debug 工具列 Call Stack 按鈕
- 顯示函數調用鏈:最頂層 = 當前函數,依序向下為呼叫者
- 雙擊任意幀 → 跳轉至對應原始碼
- 適用場景:追蹤「誰呼叫了這個函數」、分析遞歸深度、定位 Crash 來源
輔助調試巨集 (MFC 提供)
| 巨集 | 用法 | 行為差異 |
TRACE | TRACE("i=%d\n", i); | 僅 Debug 版輸出至 Output 視窗,Release 版編譯移除 |
ASSERT(expr) | ASSERT(p != NULL); | Debug 版:expr 為假 → 中斷;Release 版:完全移除 (不計算 expr) |
VERIFY(expr) | VERIFY(SetEvent(h)); | Debug 版同 ASSERT;Release 版:保留 expr 計算,但不檢查結果 |
工程配置最佳實踐
- 必須透過 AppWizard 建立專案:自動配置編譯/連結選項、預編譯標頭、偵錯資訊
- .cpp 首行強制
#include "stdafx.h":此行之前代碼會被忽略
- .c 檔案:專案設定 → C/C++ → Precompiled Headers → 「Not Using」
- 所有有回傳值的函數必須檢查回傳值:除非確定不會失敗或不關心結果
- 系統 API 失敗:立即呼叫
GetLastError()/WSAGetLastError() 取得錯誤碼
- 例外處理:使用
TRY/CATCH (MFC) 或 try/catch (C++) 捕獲異常
- 錯誤分層處理:可處理錯誤 → 底層處理並記錄;不可處理 → 回報使用者決策
總結
熟練掌握 斷點策略 (條件/資料/訊息) + 觀察視窗組合 (Watch/Memory/Variables) + 呼叫堆疊追蹤 + 單步控制,配合 TRACE/ASSERT/VERIFY 程式碼級防禦,是從「能寫代碼」邁向「寫出可靠軟體」的關鍵分水嶺。