📄 pl004.asp
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<HTML>
<HEAD>
<TITLE>程式设计基础讲座(四) ─ 向 bug 宣战, 程式中最容易潜藏 BUG 的地方</TITLE>
<META NAME="GENERATOR" CONTENT="Mozilla/3.01Gold (Win95; I) [Netscape]">
</HEAD>
<BODY BACKGROUND="back01.jpg">
<H3><FONT COLOR="#008000">程式设计基础讲座(四)</FONT></H3>
<H2 ALIGN=CENTER><FONT COLOR="#0000FF"><FONT SIZE=+3>向 bug 宣战─<BR>
程式中最容易潜藏 BUG 的地方</FONT></FONT></H2>
<P>
<HR WIDTH="100%"><A NAME="S0"></A><B><FONT COLOR="#0000FF"><FONT SIZE=+2>本文大纲</FONT></FONT></B></P>
<UL>
<TABLE WIDTH="80%" >
<TR VALIGN=TOP>
<TD VALIGN=TOP><A HREF="#s1">数学运算式</A></TD>
<TD><A HREF="#s2">程式转弯处</A></TD>
<TD><A HREF="#s3">变数</A></TD>
</TR>
</TABLE>
</UL>
<CENTER><TABLE WIDTH="95%" >
<TR>
<TD>蟑 螂 是 生 命 力 很 强 的 动 物 , 大 概 有 人 的 地 方 就 有 它 ,
虽 然 人 类 发 明 了 许 多 杀 蟑 的 方 法 , 但 蟑 螂 还 是 没 有 因 此
绝 迹 ; 电 脑 的 bug 很 像 蟑 螂 , 它 总 是 悄 悄 地 躲 进 我 们 所 开
发 的 程 式 中 , 虽 然 大 部 份 的 软 体 开 发 工 具 都 有 杀 虫 剂 (debugger),
但 bug 也 没 有 因 此 绝 迹 。
<P>我 有 一 位 很 强 壮 的 同 事 却 很 怕 蟑 螂 , 只 要 看 到 蟑 螂 ,
他 一 定 要 翻 箱 倒 柜 把 它 找 出 来 , 否 则 便 无 法 入 睡 , 这 让
我 联 想 到 是 否 有 人 为 了 一 个 bug 而 翻 遍 所 有 的 程 式 ? 对 於
小 程 式 来 说 , 这 也 许 不 是 太 难 的 事 情 , 但 对 於 大 型 程 式
, 这 却 是 不 实 际 的 , 就 像 您 要 在 几 十 层 的 大 楼 中 搜 索 一
支 蟑 螂 一 样 。 </P>
<P>我 想 应 该 先 从 蟑 螂 最 常 出 没 的 地 方 开 始 , 甚 至 在 这 些
地 方 摆 放 杀 蟑 剂 , 同 样 的 , 在 程 式 中 也 有 bug 比 较 容 易 躲
藏 的 地 方 , 我 们 首 先 要 确 定 bug 是 否 會 躲 藏 在 这 些 地 方 ,
并 且 埋 设 一 些 检 查 的 关 卡 , 只 要 bug 出 现 就 能 显 现 警 告 讯
息 。 </P>
<P>蟑 螂 的 多 寡 与 家 具 的 选 择 有 极 大 的 关 系 , 同 样 的 , bug
的 多 寡 与 开 发 程 式 的 语 言 也 有 极 大 的 关 系 , 而 在 众 多 流
通 广 泛 的 程 式 语 言 中 , 又 以 C 语 言 为 bug 的 最 爱 , 本 期 探
讨 一 般 程 式 语 言 容 易 潜 藏 bug 的 地 方 , 或 多 或 少 會 以 C 语
言 为 例 , 不 过 较 完 整 的 整 理 及 讨 论 则 留 待 以 後 。 </P>
</TD>
</TR>
</TABLE></CENTER>
<H2><A NAME="s1"></A><FONT COLOR="#0000FF">数学运算式</FONT></H2>
<UL>
<P>如 果 客 户 的 利 息 算 错 , 如 果 飞 弹 的 弹 道 算 错 , 如 果 …
, 利 用 电 脑 来 代 替 人 类 作 运 算 , 原 本 在 取 其 既 迅 速 又 准
确 的 特 性 , 为 什 麼 还 會 有 错 呢 ? </P>
</UL>
<H3><B><U><FONT COLOR="#000080">错 误 类 型 之 一 : 溢 位</FONT></U> </B></H3>
<UL>
<P>对 人 类 来 说 , 「 整 」 的 范 围 是 从 -∞ 到 +∞ , 对 电 脑 程
式 语 言 来 说 , 「 数 」 却 有 固 定 的 范 围 , 因 此 只 要 含 有 +
- × ÷ 等 运 算 符 号 ( operator) 的 运 算 式 , 其 运 算 结 果 都
可 能 超 过 电 脑 程 式 语 言 所 预 设 的 范 围 。 举 个 例 子 来 说 :
以 16 位 元 为 整 数 范 围 ( -32768 到 32767) 的 运 算 中 , 当 a >=
128时 , 运 算 式 「 a * 256」 的 结 果 ( >=32768) 即 超 出 整 数
的 范 围 , 这 就 是 所 谓 的 「 溢 位 」 ( overflow) 。 </P>
<P>溢 位 的 预 防 别 无 他 法 , 只 有 检 视 每 一 个 运 算 式 , 并 且
确 定 运 算 子 ( operand ) 的 可 能 值 不 會 使 运 算 式 造 成 溢 位
, 举 例 来 说 , 您 可 以 在 a * 256 的 运 算 式 前 面 加 上 一 段 逻
辑 判 断 , 例 如 : </P>
<UL>
<ADDRESS><FONT COLOR="#000080">If -128 <= a And a < 128 Then </FONT></ADDRESS>
<UL>
<ADDRESS><FONT COLOR="#000080">x = a * 256 </FONT></ADDRESS>
</UL>
<ADDRESS><FONT COLOR="#000080">Else </FONT></ADDRESS>
<UL>
<ADDRESS><FONT COLOR="#000080">' 停 止 运 算 </FONT></ADDRESS>
</UL>
<ADDRESS><FONT COLOR="#000080">End If</FONT></ADDRESS>
</UL>
<P>但 对 於 比 较 复 杂 的 运 算 式 , 这 种 作 法 并 不 实 际 , 举 例
来 说 , 我 们 很 难 写 出 运 算 式 「 a*a + b*10 + c」 是 否 溢 位 的
判 断 式 , 解 决 这 个 问 题 较 好 的 方 法 是 利 用 程 式 语 言 「 例
外 处 理 」 的 能 力 , 例 如 Visual Basic 就 有 「 On Error ...」 ( 当
发 生 错 误 时 , 就 … ) 的 语 法 , 以 下 是 一 个 实 例 : </P>
</UL>
<UL>
<UL>
<ADDRESS><FONT COLOR="#000080">On Error GoTo ErrorHandler</FONT></ADDRESS>
<UL>
<ADDRESS><FONT COLOR="#000080">x = a*a + b*10 + c ...</FONT></ADDRESS>
</UL>
<ADDRESS><FONT COLOR="#000080">ErrorHandler:</FONT></ADDRESS>
<ADDRESS><FONT COLOR="#000080">' 若 发 生 「 溢 位 」 的 错 误 时 , 变
数 Err 将 等 於 6 </FONT></ADDRESS>
<ADDRESS><FONT COLOR="#000080">If Err = 6 Then ... </FONT></ADDRESS>
<UL>
<ADDRESS><FONT COLOR="#000080">' 告 诉 使 用 者 发 生 溢 位 了 </FONT></ADDRESS>
<ADDRESS><FONT COLOR="#000080">Exit Sub </FONT></ADDRESS>
</UL>
<ADDRESS><FONT COLOR="#000080">Else </FONT></ADDRESS>
<UL>
<ADDRESS><FONT COLOR="#000080">... </FONT></ADDRESS>
</UL>
<ADDRESS><FONT COLOR="#000080">End If</FONT></ADDRESS>
</UL>
<P>不 过 并 不 是 所 有 的 程 式 语 言 都 具 有 「 例 外 处 理 」 的 机
制 , 以 C 语 言 为 例 , 发 生 溢 位 时 , 并 不 會 产 生 溢 位 的 错
误 , 只 是 简 单 地 把 溢 位 的 部 份 去 掉 , 表 面 看 起 来 程 式 还
能 够 正 常 地 执 行 , 但 实 际 上 执 行 的 结 果 却 是 错 误 的 , 这
是 使 用 C 语 言 应 该 特 别 注 意 的 地 方 。 </P>
</UL>
<H3><B><U><FONT COLOR="#000080">错 误 类 型 之 二 : 浮 点 数 的 不 准
确 性 </FONT></U></B></H3>
<UL>
<P>10 + 0.1 等 於 10.1, 这 麼 简 单 的 算 数 小 学 生 都 會 , 以 下 是
以 Visual Basic 所 做 的 实 验 : </P>
<UL>
<ADDRESS><FONT COLOR="#000080">x = 10.0</FONT></ADDRESS>
<ADDRESS><FONT COLOR="#000080">While x < 20.0</FONT></ADDRESS>
<UL>
<ADDRESS><FONT COLOR="#000080">x = x + 0.1</FONT></ADDRESS>
<ADDRESS><FONT COLOR="#000080">Print x</FONT></ADDRESS>
</UL>
<ADDRESS><FONT COLOR="#000080">Wend</FONT></ADDRESS>
</UL>
<P>结 果 列 印 出 来 的 值 自 11.3 以 後 就 不 完 全 正 确 了 : </P>
<UL>
<ADDRESS><FONT COLOR="#000080">...</FONT></ADDRESS>
<ADDRESS><FONT COLOR="#000080">11.1</FONT></ADDRESS>
<ADDRESS><FONT COLOR="#000080">11.2</FONT></ADDRESS>
<ADDRESS><FONT COLOR="#000080">11.3</FONT></ADDRESS>
<ADDRESS><FONT COLOR="#000080">11.40001 ← 开 始 产 生 偏 差 </FONT></ADDRESS>
<ADDRESS><FONT COLOR="#000080">11.50001</FONT></ADDRESS>
<ADDRESS><FONT COLOR="#000080">11.60001</FONT></ADDRESS>
<ADDRESS><FONT COLOR="#000080">...</FONT></ADDRESS>
</UL>
<P>这 并 非 Visual Basic 的 错 误 , 问 题 的 原 因 是 电 脑 以 有 限 的
位 数 来 表 达 无 限 的 数 值 范 围 所 产 生 的 误 差 , 虽 然 这 些 误
差 通 常 都 小 得 可 以 忽 略 它 的 存 在 , 但 仍 有 几 件 事 情 必 须
加 以 注 意 : </P>
<UL>
<P>·当 我 们 需 要 更 精 确 的 浮 点 计 算 值 时 , 先 确 定 程 式 语
言 能 否 满 足 需 求 。 </P>
<P>· 同 样 的 浮 点 运 算 式 在 不 同 机 器 、 或 不 同 的 程 式 语 言
, 可 能 因 为 其 表 达 浮 点 数 的 方 法 不 同 , 而 造 成 计 算 出 来
的 结 果 也 不 同 。 </P>
<P>· 在 逻 辑 判 断 式 中 , 尽 量 不 要 判 断 两 个 浮 点 数 是 否 相
等 , 例 如 以 下 的 回 圈 极 可 能 无 法 结 束 : </P>
<UL>
<ADDRESS><FONT COLOR="#000080">x = 10.0</FONT></ADDRESS>
<ADDRESS><FONT COLOR="#000080">While x <> 20.0</FONT></ADDRESS>
<ADDRESS><FONT COLOR="#000080">' 当 x 等 於 20.0 时 跳 出 回 圈 </FONT></ADDRESS>
<UL>
<ADDRESS><FONT COLOR="#000080">...</FONT></ADDRESS>
<ADDRESS><FONT COLOR="#000080">x = x + 0.1</FONT></ADDRESS>
</UL>
<ADDRESS><FONT COLOR="#000080">Wend</FONT></ADDRESS>
</UL>
</UL>
<P>其 原 因 是 x 虽 然 會 达 到 20.0 的 及 近 似 值 ( 以 Visual Basic
为 例 , 其 值 會 达 到 20.00004) , 但 终 究 不 等 於 20.0, 以 致 无
法 跳 出 回 圈 。 </P>
</UL>
<P><B><U><FONT COLOR="#000080"><FONT SIZE=+1>错 误 类 型 之 三 : 除 以
0</FONT></FONT></U></B></P>
<UL>
<P>当 然 没 有 人 會 笨 到 写 出 (x / 0) 这 样 的 运 算 式 , 但 类 似
(x / y) 的 运 算 式 相 信 大 家 都 写 过 , 因 此 遇 有 相 除 的 运 算
式 时 , 不 妨 先 检 查 除 数 y 是 否 为 0 的 判 断 式 , 例 如 : </P>
<UL>
<ADDRESS>If y <> 0 Then</ADDRESS>
<UL>
<ADDRESS>z = x / y</ADDRESS>
</UL>
<ADDRESS>Else</ADDRESS>
<UL>
<ADDRESS>...</ADDRESS>
</UL>
<ADDRESS>Endif </ADDRESS>
</UL>
</UL>
<P><B><U><FONT COLOR="#000080"><FONT SIZE=+1>错 误 类 型 之 四 : 弄 错
运 算 符 号 的 优 先 顺 序 </FONT></FONT></U></B></P>
<UL>
<P>数 学 运 算 式 中 , 先 × ÷ 後 + - , 相 信 大 家 都 记 得 清 清
楚 楚 , 不 过 一 个 够 格 的 程 式 语 言 , 其 所 包 含 之 运 算 功 能
应 该 不 只 这 些 , 可 能 还 包 括 幂 次 方 、 求 馀 数 、 AND、 OR、
XOR 等 , 而 各 种 程 式 语 言 在 运 算 符 号 的 优 先 顺 序 定 义 上 并
不 尽 相 同 , 举 例 来 说 , 以 下 的 运 算 式 在 BASIC 及 C 语 言 的
运 算 结 果 并 不 相 同 : ( 注 : Mod 及 % 分 别 是 BASIC 及 C 语 言
的 求 馀 数 ) </P>
<UL>
<ADDRESS><FONT COLOR="#0000FF">BASIC: 10 Mod 6 / 2 结 果 等 於 1</FONT></ADDRESS>
<ADDRESS><FONT COLOR="#0000FF">C : 10 % 6 / 2 结 果 等 於 2</FONT></ADDRESS>
</UL>
<P>这 两 种 运 算 式 的 结 果 之 所 以 不 同 , 问 题 就 出 在 运 算 符
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -