Microsoft Word - 11.doc



Similar documents
Oracle Solaris Studio makefile C C++ Fortran IDE Solaris Linux C/C++/Fortran IDE "Project Properties" IDE makefile 1.

ebook50-15

Oracle Oracle Solaris Studio IDE makefile C C++ Fortran makefile IDE Solaris Linux C/C++/Fortran Oracle IDE "P

untitled

Microsoft Word - 2CA13內文.doc

epub83-1

ch08.PDF

WebSphere Studio Application Developer IBM Portal Toolkit... 2/21 1. WebSphere Portal Portal WebSphere Application Server stopserver.bat -configfile..

概述

FY.DOC

EK-STM32F

ebook140-8

epub 61-2

1 LINUX IDE Emacs gcc gdb Emacs + gcc + gdb IDE Emacs IDE C Emacs Emacs IDE ICE Integrated Computing Environment Emacs Unix Linux Emacs Emacs Emacs Un

2 2 3 DLight CPU I/O DLight Oracle Solaris (DTrace) C/C++ Solaris DLight DTrace DLight DLight DLight C C++ Fortran CPU I/O DLight AM

新版 明解C++入門編

Microsoft Word - CIN-DLL.doc

Windows RTEMS 1 Danilliu MMI TCP/IP QEMU i386 QEMU ARM POWERPC i386 IPC PC104 uc/os-ii uc/os MMI TCP/IP i386 PORT Linux ecos Linux ecos ecos eco

SST SPAC SST SoftICE SST89C5x/SST89x554RC /564RD /SST89x516/5xRD / SoftICE SoftICE MCU SoftICE SS

威 福 髮 藝 店 桃 園 市 蘆 竹 區 中 山 里 福 祿 一 街 48 號 地 下 一 樓 50,000 獨 資 李 依 純 105/04/06 府 經 登 字 第 號 宏 品 餐 飲 桃 園 市 桃 園 區 信 光 里 民

Chapter 9: Objects and Classes

Microsoft Word - 2AF63內文.doc

int *p int a 0x00C7 0x00C7 0x00C int I[2], *pi = &I[0]; pi++; char C[2], *pc = &C[0]; pc++; float F[2], *pf = &F[0]; pf++;

BizSpark 初 创 公 司 计 划 指 南 目 录 什 么 是 BizSpark?... 1 计 划 概 述... 1 计 划 结 构 和 角 色... 1 初 创 公 司 资 格... 3 使 用 BizSpark 的 产 品 和 联 机 服 务 的 示 例 :... 3 职 责... 5

NEXT SDT2.51 C:\ARM251 SDT2.51 ARM SDT 2.51 ARM PROJECT MANAGER SDT 2


基于UML建模的管理管理信息系统项目案例导航——VB篇

言1.PDF

ARM JTAG实时仿真器安装使用指南

提问袁小兵:

穨IC-1000

Microsoft Word - InoTouch Editor编程软件手册 doc

ICD ICD ICD ICD ICD

Microsoft Word - 01.DOC

第一章.FIT)

大 綱 最 有 利 標 目 的 及 類 型 最 有 利 標 之 辦 理 方 式 準 用 最 有 利 標 取 最 有 利 標 精 神 最 有 利 標 之 類 型 及 其 相 關 規 定 適 用 最 有 利 標 準 用 最 有 利 標 及 取 最 有 利 標 精 神 作 業 程 序 及 實 務 分 析

ex

PowerPoint 簡報

<4D F736F F D20AC4FBDBDA4FBB67DA96CAABA2DA743A67EAFC5AAA95FA7B9BD5A5F2E646F63>

目錄 C ontents Chapter MTA Chapter Chapter

untitled

Process Data flow Data store External entity 6-10 Context diagram Level 0 diagram Level 1 diagram Level 2 diagram

(Microsoft Word - \251I\250D\245D\246W

附录J:Eclipse教程

目 录 软 件 概 述 软 件 用 途 软 件 运 行 系 统 配 置... 3 使 用 入 门 软 件 登 录 与 退 出 页 面 介 绍... 6 组 别 账 号 编 辑 组 别 编 辑.

1 Project New Project 1 2 Windows 1 3 N C test Windows uv2 KEIL uvision2 1 2 New Project Ateml AT89C AT89C51 3 KEIL Demo C C File

教育部高等学校教学

目錄... ivv...vii Chapter DETECT

_汪_文前新ok[3.1].doc

目 录

第一章

02

JTAG ICE PC JTAG ICE JTAG ISP... 5 IDE AVR STUDIO JTAGICE JTAGICE... 12

PROFIBUS3.doc

第 一 节 认 识 自 我 的 意 义 一 个 人 只 有 认 识 自 我, 才 能 够 正 确 地 认 识 到 自 己 的 优 劣 势, 找 出 自 己 的 职 业 亮 点, 为 自 己 的 顺 利 求 职 推 波 助 澜 ; 一 个 人 只 有 认 识 自 我, 才 能 在 求 职 中 保 持

目錄

PIC_SERVER (11) SMTP ( ) ( ) PIC_SERVER (10) SMTP PIC_SERVER (event driven) PIC_SERVER SMTP 1. E-

C/C++ - 字符输入输出和字符确认

VB程序设计教程

1 IT IT IT IT Virtual Machine, VM VM VM VM Operating Systems, OS IT

ebook39-5

AL-M200 Series

Application Note Format

Simulator By SunLingxi 2003

PTS7_Manual.PDF

深入理解otter

Outline USB Application Requirements Variable Definition Communications Code for VB Code for Keil C Practice

年 中 央 国 家 机 关 政 府 采 购 中 心 网 上 竞 价 品 目 表 中 央 国 家 机 关 政 府 采 购 中 心 2016 年 7 月 21 日 - 2 -

C/C++ - 文件IO

Basic System Administration

致理技術學院資訊管理學系專題企劃書格式建議書

一 寒 暄 : 譬 如 買 賣 領 帶 也 需 要 有 推 銷 的 槪 念 看 看 這 個 店 員 如 何 推 銷 產 品 店 員 一 見 到 客 戶 走 進 店 裡 即 說 : 先 生 您 好, 選 領 帶 呀! 歡 迎 歡 迎, 請 進 這 就 是 寒 暄 二 開 門 : 如 果 是 一 個 不

Cadence SPB 15.2 VOICE Cadence SPB 15.2 PC Cadence 3 (1) CD1 1of 2 (2) CD2 2of 2 (3) CD3 Concept HDL 1of 1

1 o o o CPU o o o o o SQL Server 2005 o CPU o o o o o SQL Server o Microsoft SQL Server 2005

《计算机网络》实验指导书

ebook140-9

CHAPTER 1

3.1 num = 3 ch = 'C' 2

技 术 支 持 电 话 传 真 电 子 邮 件 网 址 CONVERGE PRO 880/880T/840T/8i, CON

1.Product Description


上海市教育考试院关于印发新修订的


ebook

instructions.PDF

ebook50-14

Microsoft PowerPoint - os_4.ppt

RUN_PC連載_10_.doc

untitled

IC-900W Wireless Pan & Tilt Wireless Pan & Tilt Remote Control / Night Vision FCC ID:RUJ-LR802UWG

WinMDI 28

TwinCAT 1. TwinCAT TwinCAT PLC PLC IEC TwinCAT TwinCAT Masc

2/80 2

投影片 1

新・解きながら学ぶJava

投影片 1

untitled

untitled

51 C 51 isp 10 C PCB C C C C KEIL

Transcription:

除 錯 技 巧 您 將 於 本 章 學 到 以 下 各 項 : 如 何 在 Visual C++ 2010 的 除 錯 工 具 控 制 下 執 行 程 式? 如 何 逐 步 地 執 行 程 式 的 敘 述? 如 何 監 看 或 改 變 程 式 中 的 變 數 值? 如 何 監 看 程 式 中 計 算 式 的 值? 何 謂 Call Stack? 何 謂 診 斷 器 (assertion)? 如 何 使 用 診 斷 器 來 檢 查 程 式 碼? 如 何 在 程 式 中 加 入 特 殊 的 除 錯 碼? 如 何 在 原 生 C++ 程 式 中 偵 測 記 憶 體 漏 失 的 狀 況? 如 何 使 用 執 行 追 蹤 功 能, 在 C++ /CLI 程 式 中 產 生 除 錯 輸 出? 做 完 前 一 章 的 範 例, 您 已 經 跟 程 式 碼 的 bugs( 錯 誤 ) 搏 鬥 過 了 本 章 將 探 究 Visual C++ 2010 所 提 供 的 基 本 除 錯 功 能 如 何 協 助 我 們 除 錯 ; 並 且, 也 調 查 了 許 多 其 他 的 工 作, 可 協 助 由 程 式 中 找 出 錯 誤 並 消 除 錯 誤 ; 此 外, 還 有 一 些 其 他 的 方 法, 可 將 程 式 配 合 上 特 殊 的 程 式 碼, 以 便 檢 查 錯 誤

756 Visual C++ 2010 教 學 手 冊 11.1 了 解 除 錯 Bugs 是 程 式 中 的 錯 誤, 而 除 錯 (debugging) 就 是 找 出 並 消 除 錯 誤 的 過 程 現 在, 想 必 您 一 定 知 道 除 錯 是 程 式 設 計 過 程 中 的 一 部 分, 而 直 接 地 面 對 程 式 的 bugs 將 是 相 當 沉 悶 的 工 作 : 每 個 程 式 都 有 bugs, 必 須 試 著 將 它 找 出 來, 並 予 以 消 除, 這 樣 程 式 才 能 更 可 靠 且 有 效 率 請 注 意 以 下 三 項 : 程 式 的 bugs 不 一 定 會 出 現 ; 就 算 出 現, 也 可 能 不 知 道 它 在 原 始 程 式 碼 的 什 麼 地 方 ; 即 使 知 道 在 哪 裡, 可 能 也 很 難 決 定 是 什 麼 原 因 造 成 的, 而 因 此 消 除 它 即 使 是 已 經 完 整 地 測 試 過 的 程 式, 許 多 程 式 仍 然 含 有 bugs 即 使 程 式 一 直 以 來 都 能 正 確 的 執 行, 程 式 仍 可 能 隱 藏 著 bugs 通 常 在 最 困 難 的 時 候, 它 們 才 會 出 現 不 論 花 了 多 少 時 間 或 努 力 去 測 試, 複 雜 而 且 較 大 的 程 式, 通 常 還 是 有 bugs ( 這 裡 所 衡 量 大 小 並 無 精 準 的 定 義, 但 Visual C++ 2010 和 作 業 系 統 當 然 都 算 是 複 雜 且 較 大 的 程 式 ) 在 最 後 一 點 上 面 打 轉 是 很 不 明 智 的, 試 著 別 去 想 它 在 正 常 電 腦 運 算 處 理 程 序 中, 任 何 錯 誤 事 件 的 發 生 都 會 造 成 整 體 損 害 的 在 編 譯 和 連 結 階 段, 可 消 除 許 多 潛 在 的 bugs, 但 即 使 已 經 產 生 了 可 執 行 模 組, 程 式 仍 可 能 有 bugs 存 在 很 不 幸 的, 儘 管 事 實 顯 示 程 式 bugs 是 不 可 避 免 的, 但 除 錯 仍 不 是 一 門 精 準 的 技 術 但 是, 您 還 是 可 以 採 用 結 構 化 的 方 法 來 消 除 錯 誤 以 下 是 除 錯 時 可 採 用 的 四 大 策 略 : 別 重 新 發 明 輪 子! 了 解 並 運 用 Visual C++ 2010 函 式 庫 所 提 供 的 函 式 ( 或 其 他 的 商 業 軟 體 元 件 ), 讓 程 式 儘 可 能 使 用 已 經 做 過 相 當 完 整 的 測 試 的 程 式 碼 以 漸 進 的 方 式 發 展 並 測 試 程 式 個 別 地 測 試 每 個 重 要 的 類 別 和 函 式, 測 試 後, 再 將 各 別 的 程 式 碼 元 件 逐 漸 地 組 合 起 來, 這 樣 的 發 展 過 程 比 較 輕 鬆, 而 且 也 較 少 發 生 隱 藏 的 bugs 程 式 碼 的 防 護 也 就 是 撰 寫 程 式 碼 來 保 護 程 式 防 止 潛 在 的 錯 誤 例 如, 將 原 生 C++ 類 別 的 成 員 函 式 宣 告 為 const, 將 不 會 對 物 件 內 容 變 更 請 在 適 當 的 地 方 使 用 const 參 數 別 在 程 式 中 使 用 神 奇 數 字 以 需 要 的 數 值 定 義 出 會 改 變 物 件 內 容 的 const 物 件 從 程 式 開 始 就 加 入 檢 查 驗 證 資 料 以 及 條 件 等 除 錯 程 式 碼 在 本 章 將 會 更 詳 細 地 討 論 這 個 方 法

Chapter 11 除 錯 技 巧 757 結 束 一 個 程 式 時, 要 儘 可 能 地 沒 有 bugs, 而 且 人 性 化 Visual C++ 2010 提 供 一 群 強 大 的 工 具 來 尋 找 bugs 在 進 入 更 詳 細 的 技 術 前, 請 先 仔 細 地 看 看 bugs 是 如 何 產 生 的 程 式 Bugs 當 然, 程 式 引 起 bugs 的 主 要 原 因 是 您, 以 及 您 所 造 成 的 錯 誤 這 些 錯 誤 的 範 圍 從 簡 單 的 打 字 錯 誤, 到 整 個 邏 輯 的 錯 誤, 都 可 能 發 生 我 也 經 常 發 現, 很 難 相 信 自 己 竟 然 會 犯 這 樣 愚 蠢 的 錯 誤 還 沒 有 人 能 提 出 一 項 可 靠 的 方 案 來 應 付 程 式 中 的 bugs 人 類 是 創 造 的 生 物, 所 以, 您 將 一 次 又 一 次 地 發 現 自 己 創 造 了 許 多 錯 誤 挫 折 的 是, 即 使 有 許 多 錯 誤 是 那 麼 明 顯, 您 還 是 看 不 到 這 就 是 您 的 電 腦 教 導 您 要 謙 卑 的 方 式 大 體 來 說, 有 兩 種 錯 誤 的 情 形 會 導 致 程 式 產 生 bugs: 語 法 錯 誤 (Syntactic errors) 有 些 錯 誤 情 況 是 由 不 正 確 的 敘 述 格 式 而 來 的 ; 舉 例 來 說, 在 敘 述 的 結 尾 忘 記 加 上 分 號, 或 者 在 需 要 逗 號 的 地 方 使 用 冒 號 對 於 語 法 錯 誤 無 須 太 過 擔 心 編 譯 器 會 找 出 所 有 的 語 法 錯 誤, 並 且 提 示 錯 誤 為 何, 所 以 還 算 很 容 易 修 正 語 義 錯 誤 (Semantic errors) 此 種 錯 誤 發 生 時, 程 式 的 語 法 是 正 確 的, 不 過 所 做 的 事 情 並 非 我 們 所 期 望 的 對 於 程 式 來 說, 編 譯 器 沒 有 辦 法 知 道 我 們 的 意 圖, 因 此 沒 有 辦 法 找 到 語 義 上 的 錯 誤 ; 然 而, 這 種 錯 誤 常 常 會 造 成 程 式 意 外 地 終 止, 可 以 由 一 些 徵 兆 看 得 出 哪 裡 出 了 問 題 在 Visual C++ 2010 中, 其 除 錯 功 能 主 要 針 對 語 義 錯 誤 為 我 們 提 供 輔 助 語 義 錯 誤 有 可 能 相 當 難 以 捉 模 且 不 易 被 找 到 ; 例 如, 程 式 會 偶 而 地 產 生 錯 誤 的 結 果 或 者 是 突 然 地 當 掉 這 種 最 難 解 決 的 bugs 很 有 可 能 出 現 在 多 執 行 緒 (multi-thread) 的 程 式 中, 並 且 很 有 可 能 是 因 為 不 當 平 行 處 理 之 管 理 所 造 成 的 當 然, 有 許 多 bugs 在 系 統 環 境 中 ( 包 括 Visual C++ 2010 在 內 ), 但 當 程 式 無 法 運 作 時, 這 是 您 最 後 可 以 懷 疑 的 地 方 即 使 當 您 下 結 論 說 : 一 定 是 編 譯 器 或 作 業 系 統 的 錯 ; 實 際 上, 十 次 有 九 次 是 您 自 己 弄 錯 了 然 而, 在 Visual C++ 2010 裡 仍 有 些 bugs, 若 想 隨 時 更 新 為 最 新 的 版 本, 可 以 在 Microsoft 的 web 站 上 (http://msdn2.microsoft.com/en-us/visualc/default.aspx) 找 到 有 關 Visual C++ 的 資 訊 更 好 的 方 法 是, 如 果 負 擔 得 起 訂 閱 的 費 用, 可 以 訂 閱 Microsoft Developer Network 季 刊, 就 能 得 到 最 新 發 現 的 bugs 資 訊 以 及 修 正 的 更 新 內 容 若 是 可 以 為 程 式 碼 找 到 的 bugs 整 理 出 一 個 清 單 的 話, 這 樣 對 未 來 是 相 當 有 幫 助 的 以 先 前 發 生 過 的 錯 誤 來 檢 查 新 撰 寫 的 程 式 碼, 常 常 可 以 減 少 新 專 案 所 需 的 除 錯 時 間 根 據 程 式 設 計 的 性 質,bugs 有 無 窮 多 種 不 同 的 形 式, 但 某 些 類 別 是 相 當 普 遍 的, 您 可 以 完 全 地 了 解 這 些 bugs, 讓 我 們 快 速 地 瀏 覽 一 下

758 Visual C++ 2010 教 學 手 冊 一 般 的 bugs 將 bugs 分 類 的 一 個 有 效 方 法 是 根 據 它 們 引 起 的 徵 兆 來 分 類, 因 為 這 通 常 是 您 第 一 次 碰 到 這 些 bugs 的 經 驗 以 下 清 單 中 有 五 種 一 般 的 徵 兆, 但 並 未 詳 細 說 明, 等 您 在 撰 寫 程 式 的 經 驗 中 發 現 這 些 bugs 時, 可 加 入 其 他 的 說 明 : 徵 兆 資 料 損 壞 (Data corrupted) 無 法 處 理 的 例 外 情 形 (Unhandled exceptions) 程 式 卡 住 或 毀 壞 (Program hangs or crashes) 輸 入 匯 流 的 資 料 不 正 確 (Stream input data incorrect) 不 正 確 的 原 因 (Incorrect results) 可 能 引 起 的 原 因 變 數 初 始 化 失 敗 超 過 整 數 型 態 的 範 圍 不 合 法 的 指 標 當 做 陣 列 索 引 的 運 算 式 錯 誤 迴 圈 條 件 錯 誤 動 態 配 置 的 陣 列 大 小 錯 誤 類 別 的 拷 貝 建 構 函 式 指 定 運 算 子 或 解 構 函 式 失 敗 不 合 法 的 指 標 或 參 考 缺 少 catch 處 理 變 數 初 始 化 失 敗 無 限 迴 圈 不 合 法 的 指 標 重 複 釋 放 相 同 的 free store 記 憶 體 類 別 的 解 構 函 式 錯 誤 或 失 敗 使 用 者 的 輸 入 發 生 未 預 期 的 錯 誤 使 用 額 外 的 運 算 子 或 getline() 函 式 讀 取 資 料 打 字 錯 誤, 例 如 == 打 成 :=, 或 j 打 成 i 變 數 初 始 化 失 敗 超 過 整 數 型 態 的 範 圍 不 合 法 的 指 標 忽 略 了 switch 敘 述 中 的 break 看 看 有 多 少 不 同 種 類 的 錯 誤 是 由 於 不 合 法 的 指 標 所 引 起 的, 而 不 好 的 指 標 產 生 的 徵 兆 有 無 數 種, 這 可 能 是 最 常 引 起 那 些 難 找 的 bugs 的 原 因, 所 以 最 好 反 覆 的 檢 查 指 標 的 操 作 若 能 發 現 造 成 不 好 的 指 標 的 一 些 方 法, 或 許 就 能 避 免 掉 許 多 產 生 bugs 的 陷 阱 一 般 而 言, 造 成 不 好 的 指 標 的 原 因 如 下 :

Chapter 11 除 錯 技 巧 759 在 宣 告 指 標 時, 初 始 化 失 敗 在 釋 放 記 憶 體 空 間 時, 要 讓 原 來 指 向 free store 記 憶 體 的 指 標 指 向 null, 卻 失 敗 了 從 函 式 傳 回 區 域 變 數 的 位 址 由 free store 配 置 的 類 別, 其 拷 貝 建 構 函 式 和 指 定 運 算 子 失 敗 即 使 這 些 都 避 免 了, 還 是 可 能 有 bugs, 所 以, 讓 我 們 來 看 看 Visual C++ 2010 提 供 了 哪 些 協 助 除 錯 的 工 具 11.2 基 本 的 除 錯 運 作 到 目 前 為 止, 我 們 已 建 立 了 除 錯 版 程 式, 但 卻 尚 未 使 用 到 除 錯 器 (debugger) 除 錯 器 是 一 個 程 式, 以 逐 行 執 行 原 始 程 式 碼 的 方 式 來 控 制 程 式 的 執 行, 或 執 行 到 程 式 的 某 個 設 定 點 為 止 除 錯 器 會 在 程 式 的 每 個 設 定 點 停 頓, 在 繼 續 執 行 之 前, 可 以 檢 查 或 修 改 變 數 的 值, 可 以 改 變 原 始 程 式 碼, 重 新 編 譯 並 重 新 執 行, 也 可 以 在 除 錯 中 修 改 程 式 碼 當 您 修 改 程 式 碼 並 移 到 下 一 步 時, 除 錯 器 會 在 執 行 下 個 敘 述 前 自 動 重 新 編 譯 要 了 解 Visual C++ 2010 的 基 本 除 錯 能 力, 就 使 用 除 錯 器 來 執 行 一 個 程 式, 看 看 它 是 如 何 運 作 的 以 下 使 用 第 4 章 的 一 個 使 用 指 標 的 範 例 來 實 驗 :

760 Visual C++ 2010 教 學 手 冊 程 式 檔 名 :Ex4_05.cpp 若 您 的 系 統 中 已 經 有 這 個 範 例, 打 開 專 案 即 可 ; 否 則 就 得 重 新 輸 入 範 例 內 容 當 程 式 未 依 照 它 應 作 的 行 為 來 動 作 時, 除 錯 器 讓 您 能 逐 步 地 執 行 程 式, 以 便 檢 查 程 式 的 運 作, 找 出 哪 裡 發 生 了 問 題 它 也 允 許 您 在 程 式 的 執 行 期 間, 檢 查 程 式 的 資 料 狀 況 我 們 將 逐 步 執 行 範 例 程 式, 並 監 看 我 們 想 看 的 變 數 內 容 在 此 範 例 中, 要 監 看 pnumber, 以 及 pnumber 所 指 的 區 域 的 內 容 ( 也 就 是 *pnumber), 還 有 number1 和 number2 首 先, 確 定 將 此 範 例 的 程 式 建 立 的 設 定 值 (build configuration) 設 為 Win32 Debug 而 非 Win32 Release( 內 定 值 為 Win32 Release, 所 以 一 定 要 自 行 修 改 ) 在 選 擇 Project/Settings 選 項 後, 將 看 到 build configuration 的 設 定 選 項 目 前 作 用 的 build configuration 顯 示 在 旁 邊 之 標 準 工 具 列 (Standard toolbar) 的 下 拉 式 列 表 (dropdown lists) 中 要 顯 示 或 隱 藏 個 別 的 工 具 列, 只 須 以 滑 鼠 右 鍵 點 選 工 具 列, 並 從 列 表 對 工 具 列 做 選 取 或 撤 除 請 確 認 在 使 用 Debug 時, 除 錯 工 具 列 有 正 常 顯 示 除 錯 工 具 列 會 在 除 錯 器 運 作 時 自 動 地 出 現, 而 在 開 始 使 用 它 以 前, 請 先 看 看 其 中 包 含 哪 些 項 目 由 延 伸 的 下 拉 式 列 表 選 取 不 一 樣 的 設 定 值 可 以 改 變 build configuration 的 設 定 此 外, 也 可 以 使 用 Build Configuration Manager... 選 單 的 選 項 來 做 設 定 的 動 作 當 您 想 要 知 道 工 具 列 按 鈕 是 代 表 什 麼 時, 可 以 將 滑 鼠 游 標 移 到 按 鈕 上 此 時 按 鈕 的 提 示 說 明 將 顯 現 出 來, 並 說 明 該 功 能 為 何 在 專 案 中 的 Debug 版 本 設 定 檔 將 導 致 額 外 的 資 訊 被 加 入 可 執 行 程 式 檔, 供 除 錯 設 施 使 用 額 外 的 資 訊 將 儲 存 在 專 案 的 Debug 檔 案 夾 之 下 的.pdb 檔 案 中 當 您 在 測 試 完 整 的 程 式 中 不 希 望 有 過 多 的 描 述 時,'release' 版 本 的 設 定 檔 會 刪 除 這 些 除 錯 資 訊 在 專 案 版 或 企 業 版 的 Visual C++ 2010 中, 編 譯 器 在 編 譯 release 版 的 程 式 時 會 做 最 佳 化 的 處 理 ; 但 debug 版 的 程 式 在 編 譯 時 則 不 做 最 佳 化 處 理, 因 為 最 佳 化 的 過 程 牽 涉 到 重 新 排 列 程 式 碼, 或 刪 除 重 複 的 程 式 碼, 以 便 讓 程 式 更 有 效 率 因 為 最 佳 化 會 破 壞 原 始 檔 和 對 應 機 器 碼 區 段 間 的 對 應 關 係, 當 程 式 逐 步 執 行 時, 可 能 造 成 混 淆 的 情 形 發 生 檢 視 此 工 具 列 按 鈕 上 的 提 示, 將 會 對 這 些 工 具 的 功 能 有 初 步 的 概 念 然 而, 只 會 簡 單 地 使 用 它 們 第 4 章 的 範 例 並 不 需 要 使 用 所 有 的 除 錯 設 施, 只 會 用 到 一 些 比 較 重 要 的 工 具, 等 熟 悉 如 何 用 除 錯 器 來 逐 步 執 行 程 式 時, 對 於 具 有 bugs 的 程 式 有 哪 些 特 徵, 將 做 更 深 入 的 探 討

Chapter 11 除 錯 技 巧 761 選 擇 Debug Start Debugging 選 項 或 按 下 F5, 並 點 選 Debug 工 具 列 最 左 邊 的 按 鈕 都 可 以 開 啟 除 錯 器 對 於 範 例 來 說, 建 議 使 用 工 具 列 除 錯 器 有 兩 種 主 要 的 運 作 模 式 : 逐 步 執 行 程 式 碼 ( 一 次 執 行 一 個 敘 述 是 很 重 要 的 ); 或 執 行 到 原 始 程 式 的 某 個 特 殊 的 設 定 點 除 錯 器 在 原 始 程 式 碼 中 停 頓 的 設 定 點 是 由 我 們 設 定 的, 或 另 一 種 更 有 效 的 專 門 設 計 的 停 頓 點, 稱 為 中 斷 點 (breakpoint) 首 先, 先 看 看 中 斷 點 的 定 義 設 定 中 斷 點 中 斷 點 (breakpoint) 是 除 錯 器 在 程 式 中 會 自 動 執 行 暫 停 的 點 程 式 中 可 指 定 多 個 中 斷 點, 讓 程 式 在 您 感 興 趣 的 地 方 停 頓 在 每 個 中 斷 點 都 可 觀 看 程 式 的 變 數, 而 且, 若 變 數 的 值 不 對, 還 可 以 去 修 改 它 ; 但 這 是 不 切 實 際 的, 因 為 修 改 之 後,Ex4_05 程 式 的 執 行 狀 況 已 經 不 是 您 所 期 望 的 了 通 常 您 只 想 看 程 式 中 某 部 分 您 認 為 可 能 有 錯 的 特 別 區 域, 因 此, 通 常 您 會 在 您 認 為 有 錯 的 地 方 設 定 中 斷 點, 而 執 行 的 程 式 就 會 停 頓 在 第 一 個 中 斷 點 然 後 再 從 這 個 中 斷 點 開 始, 逐 步 地 執 行, 每 次 執 行 一 行 原 始 程 式 敘 述 在 原 始 程 式 的 某 行 開 端 設 定 中 斷 點, 只 要 在 想 要 停 止 執 行 的 敘 述 行 數 左 邊, 點 選 灰 色 區 塊 即 可 稱 為 雕 版 (glyph) 的 紅 色 圈 圈 會 出 現, 代 表 此 行 是 一 個 中 斷 點 若 想 要 移 除 中 斷 點, 請 以 滑 鼠 雙 擊 雕 版 在 圖 11-1 的 編 輯 窗 格 裡, 於 Ex4_05 設 定 了 兩 個 中 斷 點 圖 11-1

762 Visual C++ 2010 教 學 手 冊 在 除 錯 時, 通 常 會 設 定 多 個 中 斷 點 當 您 認 為 可 能 引 起 問 題 的 變 數 改 變 時, 就 在 中 斷 的 時 候 顯 示 該 變 數 在 指 定 中 斷 點 的 敘 述 之 前, 程 式 就 會 暫 停 執 行 編 譯 器 只 會 在 一 行 完 整 的 敘 述 前 中 斷, 並 不 會 在 敘 述 中 間 中 斷 游 標 若 放 在 一 行 的 開 端, 則 會 在 這 行 敘 述 執 行 之 前 中 斷 ; 游 標 若 放 在 沒 有 任 何 程 式 碼 的 地 方 ( 好 比 說 圖 11-1 裡 第 二 個 中 斷 點 上 面 那 一 行 ), 則 中 斷 點 會 設 定 在 那 一 行, 而 程 式 將 在 下 一 行 可 執 行 的 敘 述 執 行 前 停 頓 只 要 用 滑 鼠 按 鈕 對 紅 點 雙 擊 即 可 移 除 中 斷 點 另 外 也 可 以 在 包 含 中 斷 點 的 那 一 行 點 選 滑 鼠 右 鍵, 由 快 顯 選 單 (pop-up) 選 取 刪 除 中 斷 點 的 選 項 若 想 要 刪 除 使 用 中 之 專 案 的 所 有 中 斷 點, 可 以 選 取 Debug Delete All Breakpoints 選 項, 或 者 是 按 下 Ctrl+Shift+F9 即 可 請 注 意! 這 會 將 專 案 中 所 有 檔 案 的 中 斷 點 都 刪 除, 包 括 目 前 未 在 Editor 窗 格 打 開 的 檔 案 在 內 進 階 的 中 斷 點 當 按 下 Alt+F9, 或 者 由 Debug 工 具 列 點 取 最 右 邊 的 Windows 按 鈕, 從 列 表 選 擇 Breakpoints 後, 出 現 的 視 窗 提 供 了 另 一 種 指 定 中 斷 點 的 進 階 方 式 這 個 視 窗 如 圖 11-2 所 示 圖 11-2 工 具 列 上 的 Columns 按 鈕, 讓 我 們 可 以 在 視 窗 中 顯 示 更 多 的 欄 位 舉 例 來 說, 它 可 以 選 擇 顯 示 中 斷 點 處 的 原 始 碼 檔 案 名 稱 或 者 是 函 式 名 稱 另 外, 也 可 以 在 到 達 某 敘 述 的 執 行 時, 顯 示 目 前 發 生 的 事 情 要 設 定 中 斷 點 進 一 步 的 選 項, 請 在 Breakpoints 視 窗 中, 以 滑 鼠 右 鍵 點 選 該 中 斷 點 那 行 的 內 容, 並 且 由 快 顯 選 單 加 以 選 取 與 將 中 斷 點 設 定 在 非 敘 述 的 開 頭 一 樣, 可 以 在 某 一 個 布 林 運 算 式 為 true 的 時 候 設 定 中 斷 點 這 是 一 個 相 當 強 大 的 功 能, 不 過 也 為 程 式 增 加 可 觀 的 資 源 使 用, 因 為 運 算 式 會 不 斷 地 持 續 計 算 也 因 如 此, 即 使 在 效 能 好 的 機 器 上, 程 式 的 執 行 效 果 會 變 的 很 緩 慢 另 外, 也 可 以 讓 程 式 的 執 行 在 某 個 計 數 值 到 達 一 給 定 之 數 值 時 加 以 中 斷 這 種 功 能 對 於 迴 圈 內 的 程 式 碼 相 當 好 用, 讓 程 式 不 會 在 每 個 迴 圈 的 反 覆 流 程 裡 都 中 斷 當 您 對 中 斷 點 做 了 任 何 的 設 定, 中 斷 點 的 雕 版 會 在 中 間 出 現 + 符 號

Chapter 11 除 錯 技 巧 763 設 定 追 蹤 點 追 蹤 點 ( tracepoint) 是 一 種 特 殊 的 中 斷 點, 它 具 有 自 訂 的 相 關 動 作 若 要 建 立 追 蹤 點, 請 在 想 要 設 定 追 蹤 點 的 地 方 按 下 滑 鼠 右 鍵, 從 快 顯 選 單 中 選 取 Breakpoint Insert Tracepoint 選 項 接 著 您 會 看 到 如 圖 11-3 的 對 話 盒 如 您 所 見, 追 蹤 點 的 提 供 的 動 作 包 含 印 出 一 個 訊 息 以 及 ( 或 者 是 ) 執 行 一 個 巨 集, 並 可 在 追 蹤 點 選 擇 是 要 停 止 或 是 繼 續 執 行 在 原 始 程 式 碼 裡, 若 選 擇 到 了 追 蹤 點 仍 繼 續 執 行 的 話, 那 圖 11-3 麼 該 行 會 以 紅 色 菱 形 的 雕 版 加 以 標 示 對 話 盒 裡 的 文 字 說 明 了 如 何 指 定 要 輸 出 的 訊 息 舉 例 來 說, 若 要 輸 出 目 前 函 式 的 名 稱, 以 及 pnumber 的 數 值, 請 在 文 字 欄 裡 輸 入 以 下 的 內 容 : 當 執 行 到 追 蹤 點 時, 此 行 所 輸 出 的 結 果 會 顯 示 在 Visual Studio 應 用 程 式 視 窗 的 輸 出 窗 格 (Output pane) 中 當 選 取 Run a macro: 的 核 取 方 塊 時, 將 能 夠 由 可 取 得 之 標 準 巨 集 列 表 中 選 擇 使 用 的 巨 集 開 始 除 錯 應 用 程 式 除 錯 有 五 種 模 式, 請 在 Debug 選 單 上 加 以 選 擇, 如 圖 11-4 所 示 1. Start Debugging 選 項 ( 也 可 從 Debug 工 具 列 上 的 按 鈕 找 到 ) 單 純 地 執 行 程 式 直 到 第 一 個 中 斷 點 就 停 止 執 行 此 時, 在 檢 查 完 所 有 想 檢 查 的 項 目 之 後, 再 選 取 相 同 的 選 項 或 工 具 列 按 鈕, 則 將 繼 續 執 行 到 下 一 個 中 斷 點 使 用 這 項 功 能 即 可 從 程 式 的 一 個 中 斷 點 移 到 另 一 個 中 斷 點, 每 次 執 行 停 止 時, 可 以 檢 查 重 要 的 變 數, 若 有 需 要 則 改 變 它 們 的 值 但 若 沒 有 設 定 中 斷 點, 卻 用 這 種 方 式 來 啟 動 除 錯 器 時, 則 會 執 行 完 整 個 程 式 而 沒 有 任 何 圖 11-4

764 Visual C++ 2010 教 學 手 冊 暫 停 當 然, 以 這 種 方 式 開 始 除 錯 並 不 表 示 接 下 來 一 定 要 繼 續 使 用 這 種 模 式, 每 次 暫 停 時 都 可 以 改 選 其 他 的 任 何 一 種 除 錯 模 式 來 繼 續 除 錯 2. Debug 選 單 中 的 Attach to Process 選 項, 讓 您 能 夠 對 一 個 正 在 執 行 的 程 序 除 錯 這 個 選 項 將 顯 示 在 您 的 機 器 上 所 執 行 的 一 連 串 程 序, 可 以 選 擇 想 要 進 行 除 錯 的 程 序 這 是 專 為 進 階 的 使 用 者 設 計 的, 而 您 應 該 避 免 試 用 它, 除 非 知 道 自 己 在 做 什 麼 萬 一 干 擾 到 作 業 系 統 中 某 些 重 要 的 程 序, 很 可 能 讓 機 器 卡 死 或 引 起 其 他 的 問 題 3. Step Into 選 項 ( 也 可 從 Debug 工 具 列 上 的 按 鈕 找 到 ) 會 一 次 執 行 一 個 程 式 敘 述, 每 個 程 式 區 塊 都 執 行, 包 含 裡 面 所 呼 叫 的 每 個 函 式 若 整 個 除 錯 過 程 都 使 用 這 種 模 式 就 有 點 討 厭, 因 為 它 也 會 執 行 匯 流 輸 出 的 函 式 庫 函 式 裡 的 每 行 程 式 碼, 但 我 們 並 不 關 心 那 些 程 式, 因 為 那 些 不 是 我 們 寫 的 有 相 當 多 的 函 式 庫 函 式 是 用 組 合 語 言 寫 的, 包 括 許 多 支 援 輸 入 / 輸 出 匯 流 的 程 式 組 合 語 言 函 式 每 次 執 行 一 個 機 器 指 令, 這 將 會 浪 費 許 多 時 間 4. Step Over( 也 可 從 Debug 工 具 列 上 的 按 鈕 找 到 ) 會 單 純 地 執 行 程 式 裡 的 每 一 個 敘 述, 一 次 一 個, 並 執 行 所 有 匯 流 運 作 的 程 式 碼 ( 或 在 敘 述 中 可 能 呼 叫 的 其 他 函 式 ), 但 執 行 這 些 函 式 時 並 不 會 暫 停 另 外, 還 有 一 個 未 出 現 在 Debug 選 單 上 的 第 六 種 除 錯 模 式 請 在 任 一 行 程 式 碼 按 滑 鼠 右 鍵, 並 從 內 文 選 單 中 選 擇 Run to Cursor 選 項 由 它 的 名 稱 很 容 易 知 道 此 種 模 式 所 提 供 的 功 能 程 式 會 執 行 到 游 標 所 在 的 位 置, 然 後 中 斷 執 行 讓 我 們 檢 查 或 修 改 程 式 裡 的 變 數 無 論 以 哪 種 模 式 開 始 除 錯, 都 可 以 由 最 接 近 的 中 斷 點 開 始, 以 五 種 模 式 的 任 一 種 繼 續 執 行 現 在 就 來 範 例 程 式 若 要 使 用 Step Into 選 項, 請 點 選 適 當 的 選 項, 或 者 工 具 列 按 鈕, 或 者 是 按 下 F11 來 開 始 執 行 程 式 在 短 暫 的 暫 停 以 後 ( 假 設 您 已 經 建 立 完 成 專 案 的 build),visual C++ 2010 會 切 換 到 除 錯 模 式 當 除 錯 器 開 始 作 業 時,Editor 視 窗 下 面 會 出 現 兩 個 具 有 頁 籤 的 視 窗 無 論 哪 一 個 視 窗, 都 可 以 在 任 何 時 間 選 擇 任 一 個 頁 籤, 觀 看 需 要 的 資 訊 除 錯 器 開 始 作 業 時, 要 顯 示 哪 些 視 窗 都 可 以 自 訂 完 整 的 視 窗 列 表 出 現 在 Debug Windows 選 單 的 下 拉 式 列 表 中 左 邊 的 Autos 視 窗 會 顯 示 目 前 執 行 中 之 函 式 的 自 動 變 數 目 前 數 值 右 邊 的 Call Stack 視 窗 可 以 識 別 目 前 的 函 式 呼 叫, 不 過 同 一 個 視 窗 內 的 Output 頁 籤 可 能 更 有 趣 在 Editor 窗 格 中, 可 以 看 到 main() 函 式 的 左 大 括 號 以 箭 頭 加 以 標 示, 代 表 程 式 目 前 執 行 的 位 置, 如 圖 11-5 所 示

Chapter 11 除 錯 技 巧 765 圖 11-5 此 外, 還 可 以 看 到 第 11 行 的 中 斷 點 以 及 第 17 行 的 追 蹤 點 對 此 時 來 說, 程 式 執 行 到 的 地 方 還 不 能 觀 看 任 何 變 數, 因 為 目 前 變 數 都 還 不 存 在 在 程 式 執 行 到 變 數 的 宣 告 以 前, 都 無 法 觀 察 或 更 改 變 數 對 於 處 理 I/O( 輸 入 / 輸 出 ) 的 匯 流 函 式 來 說, 要 避 免 一 口 氣 完 成 其 所 有 的 程 式 碼 執 行, 可 以 使 用 Step Over 功 能, 讓 其 執 行 到 下 一 個 中 斷 點 中 止 檢 查 變 數 值 定 義 您 想 要 檢 查 的 變 數, 稱 為 變 數 的 setting a watch 在 設 定 任 何 watches 之 前, 應 該 先 在 程 式 中 宣 告 變 數 我 們 可 用 三 次 的 Step Over 來 執 行 變 數 的 宣 告 使 用 Step Over 選 項 工 具 列 圖 示, 或 是 按 F10 三 次, 之 後, 箭 頭 將 指 示 在 第 11 行 的 敘 述 開 端 : 現 在 若 觀 看 Autos 視 窗, 應 該 會 看 到 圖 11-6 的 內 容 ( 雖 然 &number1 的 值 ( 是 一 個 記 憶 體 位 址 ), 在 您 的 系 統 所 出 現 的 值 跟 書 上 的 可 能 不 同 ) 請 注 意!&number1 和 pnumber 並 不 相 等, 因 為 將 pnumber 設 定 為 number1 的 位 址 的 敘 述 ( 箭 頭 目 前 正 指 著 這 行 ), 目 前 尚 未 執 行 函 式 的 第 一 行 將 pnumber 初 始 化 為 null 指 標, 所 以 它 的 內 容 是 0; 若 沒 有 將 指 標 初 始 化, 它 會 包 含 無 效 的 值 可 能 是 上 個 程 式 殘 留 在 某 4 個 byte 的 記 憶 體 裡 面 的 值 ; 當 然, 也 可 能 是 0, 但 基 本 上 是 任 意 數

766 Visual C++ 2010 教 學 手 冊 您 可 選 擇 Debug Windows 選 單, 在 視 窗 的 左 下 角 顯 示 以 下 五 個 頁 籤 : Autos 頁 籤 顯 示 目 前 敘 述 及 之 前 執 行 後 所 留 下 來 的 自 動 變 數 ( 換 句 話 說, 在 編 輯 視 窗 的 箭 頭 之 前 的 敘 述 ) 圖 11-6 Locals 頁 籤 顯 示 目 前 函 式 的 區 域 變 數 值 一 般 來 說, 在 追 蹤 程 式 時, 新 變 數 會 進 到 這 個 範 圍 裡, 然 後 離 開 定 義 的 區 域 時, 變 數 又 超 出 這 個 範 圍 就 此 範 例 的 狀 況 而 言, 此 視 窗 會 一 直 顯 示 number1 number2 以 及 pnumber 的 值, 因 為 這 裡 只 有 一 個 main() 函 式, 也 只 有 一 個 程 式 區 塊 Threads 頁 籤 讓 我 們 能 夠 在 進 階 的 應 用 程 式 中, 檢 查 與 控 制 執 行 緒 (thread) Modules 頁 籤 會 列 出 目 前 執 行 之 程 式 碼 模 組 的 詳 細 資 料 若 應 用 程 式 發 生 異 常 錯 誤, 可 以 檢 視 此 頁 籤 的 Address 欄 位, 確 定 發 生 問 題 的 記 憶 體 位 址 並 加 以 比 較, 用 以 判 斷 哪 個 模 組 出 了 問 題 可 以 在 Watch1 頁 籤 加 入 想 要 觀 察 的 變 數 請 在 視 窗 點 選 其 中 的 一 欄, 然 後 輸 入 變 數 名 稱 除 此 之 外, 也 可 以 觀 察 一 個 C++ 運 算 式 的 數 值, 輸 入 的 方 式 與 變 數 是 相 同 的 透 過 Debug Windows Watch 選 項 最 多 可 以 加 上 額 外 三 個 Watch 視 窗 您 可 能 已 注 意 到 : 在 Autos 視 窗 中, pnumber 名 稱 前 有 一 個 加 號, 這 表 示 此 變 數 還 有 其 他 資 訊 可 顯 示 例 如, 一 個 陣 列 或 指 標 或 類 別 物 件 就 此 範 例 的 狀 況 而 言, 可 以 按 變 數 前 的 加 號 來 展 開 指 圖 11-7 標 變 數 的 其 他 資 訊 按 F10 或 是 按 pnumber 前 的 +, 除 錯 器 將 顯 示 儲 存 在 指 標 所 存 的 記 憶 體 位 址 的 值, 如 圖 11-7 所 示 Autos 視 窗 會 自 動 地 提 供 我 們 所 有 需 要 的 資 料, 顯 示 記 憶 體 位 址 以 及 儲 存 在 該 位 址 的 數 值 整 數 值 可 被 顯 示 為 十 進 制 或 十 六 進 制, 若 要 切 換, 只 要 在 Autos 頁 籤 的 任 何 地 方 按 右 鍵, 然 後 從 快 顯 選 單 加 以 選 擇 即 可 選 擇 Locals 頁 籤 可 看 到 目 前 函 式 的 區 域 變 數 Visual C++ 2010 的 其 他 除 錯 設 施 中, 還 有 其 他 檢 查 變 數 的 方 法

Chapter 11 除 錯 技 巧 767 在 編 輯 視 窗 中 觀 看 變 數 若 要 觀 看 單 一 變 數 的 值, 且 該 變 數 在 目 前 的 文 字 編 輯 視 窗 中 可 看 到, 則 最 簡 單 的 觀 看 方 法 是 讓 游 標 在 變 數 上 停 留 一 會, 之 後 會 彈 跳 出 一 個 提 示, 顯 示 目 前 的 變 數 值 同 樣 的 方 法 也 適 用 於 較 複 雜 的 運 算 式, 先 將 整 個 運 算 式 反 白, 再 將 游 標 移 到 反 白 區 上 停 留 一 會, 則 又 會 彈 跳 出 一 個 提 示, 顯 示 目 前 運 算 式 的 值 試 著 將 運 算 式 *pnumber*10 反 白, 將 游 標 移 到 反 白 區 上, 運 算 式 目 前 的 計 算 結 果 就 顯 示 出 來 了 請 注 意, 若 運 算 式 不 完 整 的 時 候 好 比 說 反 白 的 區 域 沒 有 把 pnumber 提 領 用 的 * 加 入, 或 者 只 是 將 *pnumber* 反 白, 那 麼 數 值 結 果 都 不 會 出 現 改 變 變 數 的 值 Watch 視 窗 也 允 許 在 觀 看 變 數 時, 改 變 變 數 的 值 當 顯 示 的 值 很 明 顯 地 有 問 題 時, 可 能 是 因 為 程 式 有 bugs, 也 可 能 因 為 尚 未 執 行 任 何 程 式 碼, 此 時 可 以 將 值 加 以 修 正 若 設 為 正 確 的 值, 則 程 式 還 能 再 繼 續 下 去, 這 樣 一 來, 就 可 以 做 更 多 的 測 試, 或 找 出 更 多 的 bugs 若 涉 及 多 次 重 複 的 迴 圈 時, 例 如 30000 次, 則 可 將 迴 圈 計 算 器 設 為 29995, 只 要 逐 步 執 行 後 面 幾 次, 並 驗 證 迴 圈 能 正 確 終 止 就 夠 了 按 30000 次 的 F10 真 的 會 累 死 人! 另 外, 還 有 一 項 很 有 用 的 功 能 是 在 執 期 間, 故 意 將 變 數 設 為 會 引 起 錯 誤 的 值, 這 樣 可 以 檢 查 程 式 中 負 責 處 理 錯 誤 的 程 式 碼, 否 則 有 些 時 候 這 些 功 能 是 沒 有 機 會 測 試 的 要 在 Watch 視 窗 更 改 變 數 的 值, 只 要 在 變 數 值 顯 示 的 地 方 按 兩 下, 然 後 輸 入 新 值 即 可 若 要 改 變 的 變 數 是 陣 列 的 元 素, 必 須 按 陣 列 名 稱 前 的 加 號, 展 開 整 個 陣 列, 然 後 再 更 改 元 素 的 值 若 要 讓 變 數 的 值 以 十 六 進 位 的 方 法 顯 示, 可 以 直 接 輸 入 十 六 進 位 的 數 值, 或 在 十 進 位 數 值 之 前 加 上 0n( 零 後 面 加 上 n), 例 如 輸 入 A9 或 是 0n169; 若 只 輸 入 169, 則 會 解 釋 為 十 六 進 位 的 數 值 很 自 然 地, 不 管 願 意 與 否 都 應 該 小 心 地 將 新 值 丟 到 程 式 中 除 非 能 確 定 地 知 道 您 所 做 的 改 變 會 造 成 什 麼 影 響, 否 則, 最 後 可 能 因 為 許 多 奇 怪 的 行 為 而 結 束 程 式, 這 未 必 能 讓 程 式 更 接 近 能 運 作 的 狀 態 也 許 您 會 發 現, 在 除 錯 模 式 下 多 執 行 一 些 範 例 ( 可 以 用 前 面 幾 章 的 範 例 來 練 習 ), 對 您 是 很 幫 助 的 這 將 使 您 對 於 除 錯 器 在 許 多 不 同 的 狀 況 下 的 運 作, 有 更 完 整 的 概 念 監 看 變 數 和 運 算 式, 對 於 找 出 程 式 的 問 題 是 相 當 有 幫 助 的, 但 要 尋 找 和 摧 毀 bugs 還 有 許 多 更 有 幫 助 的 方 式 接 下 來, 讓 我 們 看 看 如 何 在 程 式 中 加 入 某 些 程 式 碼, 以 提 供 更 多 關 於 何 時 及 為 何 會 發 生 錯 誤 的 資 訊 11.3 加 入 除 錯 程 式 碼 一 個 程 式 涉 及 了 相 當 多 的 程 式 碼, 所 以 一 定 要 加 入 額 外 的 程 式 碼 來 突 顯 可 能 的 bugs, 並 提 供 記 錄 輸 出, 協 助 找 出 bugs 在 哪 裡 到 底 有 哪 些 bugs? 哪 一 部 分 的 程 式 可 能 有

768 Visual C++ 2010 教 學 手 冊 bugs? 對 於 這 些, 在 有 任 何 想 法 之 前, 您 不 會 想 逐 步 地 執 行 程 式 當 測 試 程 式 時, 唯 一 需 要 的 東 西 就 是 程 式 碼, 一 旦 您 覺 得 程 式 能 夠 完 全 地 運 作, 就 不 再 需 要 除 錯 程 式 碼 了, 而 且 也 不 希 望 這 些 除 錯 碼 在 最 後 產 生 的 程 式 版 本 執 行 時, 造 成 多 餘 的 負 擔, 或 產 生 某 些 不 必 顯 示 的 輸 出 訊 息 因 此, 額 外 的 除 錯 程 式 碼 只 會 在 debug( 除 錯 ) 版 的 程 式 中 運 作, 不 會 在 真 正 release 版 的 程 式 中 運 作 由 debug 版 所 產 生 的 輸 出, 應 該 可 以 提 供 一 些 線 索 例 如 : 什 麼 會 引 起 問 題? 而 且, 若 程 式 作 好 了 除 錯 程 式 的 工 作, 它 將 會 給 您 一 些 很 好 的 意 見, 指 示 出 程 式 的 哪 個 部 分 發 生 了 錯 誤 之 後, 就 可 以 使 用 除 錯 器 找 出 某 種 性 質 的 bugs 以 及 它 的 所 在 位 址, 然 後 修 正 它 第 一 種 檢 查 程 式 行 為 的 方 法 是 由 C++ 的 函 式 庫 函 式 所 提 供 的 使 用 診 斷 器 標 準 函 式 庫 標 頭 檔 cassert 宣 告 了 一 個 assert() 函 式, 當 一 個 特 別 的 前 端 處 理 代 碼 NDEBUG 沒 有 被 定 義 時, 即 可 用 它 來 檢 查 程 式 的 邏 輯 條 件 此 函 式 的 宣 告 如 下 : 函 式 的 指 定 引 數 為 檢 查 條 件, 但 若 特 別 的 前 端 處 理 代 碼 NDEBUG 被 定 義 時,assert() 函 式 就 會 無 效 代 碼 NDEBUG 會 自 動 被 定 義 在 程 式 的 release 版 本 中, 但 不 會 定 義 在 debug 版 本 中 ; 因 此, 在 debug 版 本 的 程 式 中, 診 斷 器 會 檢 查 它 的 引 數, 但 在 release 版 本 中, 診 斷 器 卻 不 做 任 何 事 在 debug 版 本 中, 若 要 關 閉 診 斷 器, 可 使 用 #define 假 指 令 將 NDEBUG 加 入 程 式 裡 為 了 要 達 到 它 的 效 果, 必 須 將 #define NDEBUG 放 在 #include <cassert> 之 前, 如 以 下 敘 述 所 示 : 若 傳 給 assert() 為 引 數 的 運 算 式 不 是 0( 即 為 true), 則 函 式 不 做 任 何 事 ; 否 則, 就 輸 出 診 斷 訊 息 顯 示 的 內 容 有 : 運 算 式 執 行 失 敗 原 始 檔 名 稱 原 始 檔 發 生 錯 誤 的 行 號 顯 示 完 診 斷 訊 息 之 後,assert() 會 呼 叫 abort() 來 結 束 程 式 以 下 是 一 個 使 用 診 斷 器 的 函 式 範 例 :

Chapter 11 除 錯 技 巧 769 呼 叫 append() 函 式, 並 以 null 指 標 作 為 引 數, 在 我 們 機 器 上 所 產 生 的 診 斷 說 明 如 下 : 診 斷 器 也 顯 示 一 個 訊 息 方 塊, 提 供 以 下 三 種 選 項, 如 圖 11-8 所 示 : 選 擇 Abort 按 鈕 則 立 刻 結 束 程 式,Retry 按 鈕 則 啟 動 Visual C++ 2010 的 除 錯 器, 逐 步 地 執 行 程 式, 找 出 更 多 為 何 診 斷 失 敗 的 原 因 原 則 上,Ignore 按 鈕 允 許 程 式 繼 續 執 行 而 不 管 有 沒 有 錯 誤, 但 通 常 這 是 不 明 智 的 選 擇, 因 為 它 的 執 行 結 果 應 該 不 是 您 所 預 期 的 圖 11-8 任 何 一 種 邏 輯 運 算 式 都 可 作 為 assert() 的 引 數, 可 以 比 較 數 值 檢 查 指 標 驗 證 物 件 型 態, 或 任 何 有 助 於 檢 查 程 式 是 否 能 正 確 運 作 的 方 式 當 某 些 邏 輯 條 件 失 敗 時, 產 生 一 些 訊 息 是 有 幫 助 的, 但 通 常 需 要 相 當 多 的 診 斷 才 能 偵 測 到 bugs 並 修 正 它 讓 我 們 看 看 怎 樣 才 能 加 入 更 普 遍 性 的 診 斷 程 式 碼 加 入 您 自 己 的 除 錯 程 式 碼 使 用 前 端 處 理 程 式 假 指 令, 以 便 安 排 加 入 任 何 想 要 加 入 的 程 式 碼, 它 只 在 會 debug 版 本 編 譯 和 執 行 ; 除 錯 程 式 碼 在 release 版 本 將 被 完 全 地 省 略, 因 此 對 測 試 程 式 的 效 率 完 全 沒 有 影 響 您 可 以 不 用 NDEBUG 代 碼 作 為 包 含 除 錯 程 式 碼 的 控 制 機 制, 因 為 此 代 碼 是 用 來 控 制 標 準 函 式 庫 的 assert() 函 式 的 運 作, 正 如 上 一 節 所 討 論 的 另 一 種 更 好 更 正 面 的 控 制 機 制 是 使 用 另 一 個 前 端 處 理 代 碼 _DEBUG,Visual C++ 會 自 動 將 它 加 在 debug 版 的 程 式 裡, 但 不 會 加 在 release 版 本 裡 除 錯 時, 只 要 使 用 #ifdef/#endif 這 對 前 端 處 理 程 式 假 指 令, 加 上 測 試 用 的 _DEBUG 代 碼, 將 要 編 譯 和 執 行 的 程 式 碼 圍 起 來 即 可, 如 以 下 敘 述 所 示 在 #ifdef 和 #endif 間 的 程 式 碼, 唯 有 _DEBUG 代 碼 被 定 義 時 才 會 編 譯 這 表 示, 一 旦 程 式 碼 完 全 測 試 過 了, 即 可 從 debug 版 的 程 式 碼 完 整 地 清 除 所 有 除 錯 碼, 產 生 release 版 的 程 式 除 錯 程 式 碼 可 以 做 任 何 對 各 個 除 錯 階 段 有 益 的 事, 從 簡 單 的 輸 出 一 個 訊 息, 到 依 序 執 行 的 記 錄 ( 例 如 每 個 函 式 被 呼 叫 時 都 記 錄 下 來 ), 以 避 免 額 外 的 證 實 計 算 和 資 料 驗 證, 或 呼 叫 別 的 函 式 來 提 供 除 錯 輸 出

770 Visual C++ 2010 教 學 手 冊 當 然, 在 原 始 程 式 檔 中, 可 能 有 好 幾 個 像 這 樣 的 除 錯 區 塊, 也 可 能 使 用 自 訂 的 前 端 處 理 代 碼 來 提 供 更 多 選 擇 性, 決 定 包 含 哪 些 程 式 碼 這 樣 做 的 一 個 理 由 是 : 如 果 某 些 除 錯 程 式 碼 產 生 許 多 的 輸 出 時, 可 以 在 真 的 需 要 時 才 產 生 這 些 輸 出 另 一 種 可 提 供 更 高 階, 而 且 更 詳 細 的 除 錯 輸 出, 每 個 執 行 都 可 挑 選 想 要 產 生 的 輸 出, 但 即 使 有 這 些 實 例, 使 用 _DEBUG 代 碼 來 提 供 控 制 除 錯 碼, 仍 是 一 種 很 好 的 想 法, 因 為 可 以 確 定 的 是 它 會 自 動 讓 release 程 式 中 完 全 沒 有 除 錯 碼 的 負 擔 以 下 是 一 個 簡 單 的 例 子 假 設 用 兩 個 自 訂 的 代 碼 來 控 制 除 錯 碼 MYDEBUG 管 理 一 般 的 除 錯 碼,VOLUMEDEBUG 控 制 產 生 許 多 輸 出 的 除 錯 程 式 碼, 而 且 這 些 輸 出 只 在 您 想 要 產 生 時 才 產 生 只 有 _DEBUG 被 定 義 時 才 定 義 這 些 代 碼 : 要 避 免 大 量 的 除 錯 輸 出, 只 要 將 VOLUMEDEBUG 定 義 變 成 註 解, 而 不 管 有 沒 有 定 義 _DEBUG 代 碼 當 程 式 有 許 多 原 始 檔 案 時, 您 可 能 發 現 將 除 錯 代 碼 集 中 在 標 頭 檔 是 很 方 便 的 作 法, 之 後 只 要 在 每 個 包 含 除 錯 碼 的 程 式 中 #include 標 頭 檔 即 可 接 下 來, 介 紹 一 個 簡 單 的 範 例, 看 看 實 際 上 加 入 程 式 的 除 錯 碼 會 如 何 運 作 TRY IT OUT 加 入 除 錯 的 程 式 碼 為 了 探 究 這 些 除 錯 碼 以 及 某 些 常 用 的 除 錯 方 法, 以 下 利 用 一 個 簡 單 且 包 含 一 些 能 被 找 出 並 消 除 的 bugs 的 程 式 範 例 因 此, 您 必 須 對 本 章 其 餘 地 方 的 所 有 程 式 碼 有 所 懷 疑, 特 別 是 當 那 個 程 式 不 需 符 合 良 好 的 程 式 設 計 習 慣 時 要 試 驗 除 錯 的 運 作, 首 先 從 定 義 類 別 著 手, 此 類 別 表 示 一 個 人 的 名 字 ; 接 著 測 試 它 的 動 作 在 此 程 式 中 有 許 多 錯 誤, 所 以 請 保 持 耐 心 去 修 正 那 些 顯 然 有 錯 的 程 式 碼 這 個 想 法 是 要 讓 您 練 習 除 錯 運 作, 找 出 程 式 的 錯 誤 然 而, 實 際 上 在 執 行 程 式 時, 有 許 多 的 bugs 是 非 常 明 顯 的, 此 時 則 不 需 使 用 除 錯 器 或 其 他 額 外 的 程 式 碼 來 突 顯 它 們 請 先 建 立 一 個 Win32 Console 應 用 程 式 Ex11_01, 並 且 改 變 Character Set 專 業 特 性 為 Not Set 接 下 來, 再 加 入 一 個 自 訂 的 Name.h 標 頭 檔, 裡 面 包 含 Name 類 別 的 定 義, Name 類 別 有 兩 個 資 料 成 員, 是 兩 個 指 標, 分 別 指 向 某 人 的 姓 和 名 要 宣 告 Name 陣 列 物 件 時, 除 了 內 定 建 構 函 式 之 外, 必 須 提 供 其 他 的 建 構 函 式 為 了 比 較 Name 物 件, 所 以 在 類 別 中 加 入 多 載 運 算 子 此 外, 為 了 方 便 起 見, 必 須 可 將 完 整 的 名 稱 視 為 一 個 字 串, 直 接 從 類 別 中 取 出, 因 此, 位 於 Name.h 檔 案 中 的 Name 類 別 定 義 大 致 如 以 下 敘 述 所 示 :