?? pl004.asp
字號:
號 的 優 先 順 序 上 , 其 中 BASIC 的 / 其 優 先 順 序 大 於 Mod, 所
以 結 果 等 於 10 Mod (6 / 2), 而 C 語 言 的 / 其 優 先 順 序 與 % 相
同 , 所 以 運 算 結 果 等 於 (10 % 6) / 2。 </P>
<P>以 上 提 出 BASIC 及 C 語 言 的 差 異 , 并 不 是 要 您 去 熟 悉 所
有 程 式 語 言 在 運 算 元 上 的 優 先 順 序 , 只 是 提 醒 您 在 數 學
運 算 式 中 應 該 注 意 這 件 事 , 而 最 保 險 的 方 法 是 利 用 (),
只 要 是 沒 有 把 握 而 又 必 須 優 先 運 算 的 運 算 符 號 , 一 概 加
上 () 就 對 了 。 </P>
</UL>
<P><B><U><FONT COLOR="#000080"><FONT SIZE=+1>錯 誤 類 型 之 五 : 不 同
型 別 的 運 算 </FONT></FONT></U></B></P>
<UL>
<P>一 支 雞 加 一 支 雞 等 於 兩 支 雞 , 但 一 支 雞 加 一 條 狗 等 於
什 麼 呢 ? 這 就 好 像 "ABC" 加 100 是 沒 有 意 義 的 , 大
部 份 的 情 形 , 型 態 「 不 同 」 的 變 數 是 不 能 在 一 起 運 算 的
, 不 過 為 了 增 加 程 式 撰 寫 上 的 彈 性 , 有 一 大 半 的 程 式 語
言 允 許 型 態 「 相 容 」 的 變 數 互 相 作 運 算 , 例 如 整 數 與 浮
點 數 的 加 減 , 有 時 候 這 的 確 很 方 便 , 但 這 個 方 便 之 門 也
開 啟 了 bug 之 門 。 </P>
<P><FONT COLOR="#800000">錯 誤 實 例 之 一 :</FONT> </P>
<P>A 先 生 過 去 一 直 以 BASIC 開 發 程 式 , 最 近 因 工 作 需 要 改
用 C 語 言 , 他 將 一 「 計 算 平 均 數 」 的 程 式 段 直 接 由 BASIC
改 成 C 。 </P>
<UL>
<ADDRESS><FONT COLOR="#000080">' 原 BASIC 程 式 </FONT></ADDRESS>
<ADDRESS><FONT COLOR="#000080">Dim sum As Integer </FONT></ADDRESS>
<ADDRESS><FONT COLOR="#000080">Dim average As Single </FONT></ADDRESS>
<ADDRESS><FONT COLOR="#000080">sum = 0 </FONT></ADDRESS>
<ADDRESS><FONT COLOR="#000080">For i = 1 To 10 </FONT></ADDRESS>
<UL>
<ADDRESS><FONT COLOR="#000080">sum = sum + I </FONT></ADDRESS>
</UL>
<ADDRESS><FONT COLOR="#000080">Next </FONT></ADDRESS>
<ADDRESS><FONT COLOR="#000080">average = sum / 10 </FONT></ADDRESS>
</UL>
<P>// 轉 換 成 C 以 後 的 程 式 </P>
<UL>
<ADDRESS><FONT COLOR="#000080">int sum; </FONT></ADDRESS>
<ADDRESS><FONT COLOR="#000080">float average; </FONT></ADDRESS>
<ADDRESS><FONT COLOR="#000080">sum = 0 ; </FONT></ADDRESS>
<ADDRESS><FONT COLOR="#000080">for( i = 1; i <= 10; i++) </FONT></ADDRESS>
<UL>
<ADDRESS><FONT COLOR="#000080">sum = sum + i ; </FONT></ADDRESS>
</UL>
<ADDRESS><FONT COLOR="#000080">average = sum / 10 ; </FONT></ADDRESS>
</UL>
<P><FONT COLOR="#800000">錯 誤 說 明 : </FONT></P>
<P>請 注 意 這 個 程 式 中 的 sum 是 整 數 , 而 average 是 浮 點 數 ,
一 般 來 說 , 浮 點 數 的 數 值 范 圍 比 整 數 來 得 大 , 所 以 將 整
數 指 定 給 浮 點 數 并 不 會 有 什 麼 問 題 , 這 個 例 子 所 出 的 問
題 其 實 是 在 除 號 (/)上 面 , 對 於 BASIC 來 說 , 以 / 所 運 算 出
來 的 結 果 均 表 示 成 「 浮 點 數 」 , 所 以 「 sum / 10」 所 得 到
的 結 果 是 55.0 / 10 = 5.5, 至 於 C 語 言 則 會 先 檢 查 / 號 兩 邊
的 資 料 型 態 , 然 後 再 選 擇 數 值 范 圍 較 大 的 資 料 型 別 作 為
運 算 的 根 據 , 以 「 sum / 10」 來 說 , 兩 邊 的 資 料 型 態 均 為
整 數 , 所 以 執 行 時 采 整 數 的 運 算 方 式 , 於 是 結 果 變 成 55
/ 10 = 5。 </P>
<P><FONT COLOR="#008000">注 : BASIC 的 另 一 個 運 算 符 號 \ 也 是 用
來 當 作 除 號 , 但 其 運 算 結 果 則 一 概 表 示 成 整 數 , 以 55 \
10 為 例 , 其 結 果 等 於 5, 而 55.0 \ 10 的 結 果 也 是 5。 </FONT></P>
<P>如 果 想 讓 前 面 的 C 程 式 得 到 正 確 的 結 果 有 三 個 方 法 :
(1) 把 被 除 數 sum 的 資 料 型 態 改 成 浮 點 數 , (2) 在 被 除 數 sum
的 前 面 加 上 (float), 意 思 是 在 運 算 前 強 制 將 sum 轉 成 浮 點
數 , (3) 把 除 數 10 改 成 浮 點 型 態 的 10.0。 </P>
<P><FONT COLOR="#800000">錯 誤 實 例 之 二 : </FONT></P>
<P>中 文 字 是 由 兩 個 字 元 所 組 成 的 , 其 中 第 一 個 字 元 一 定
大 於 等 於 128( = 16 進 位 的 80) , 以 下 的 C 語 言 程 式 段 就 用
這 個 原 則 來 判 斷 字 串 第 一 個 字 是 否 為 中 文 字 。 </P>
<UL>
<ADDRESS><FONT COLOR="#000080">char the_word[] = "我 是 中 文 字 ";
</FONT></ADDRESS>
<ADDRESS><FONT COLOR="#000080">if ( the_word[0] >= 128 ) </FONT></ADDRESS>
<UL>
<ADDRESS><FONT COLOR="#000080">printf("%s 的 第 一 個 字 是 中 文
", the_word) ; </FONT></ADDRESS>
</UL>
</UL>
<P>結 果 printf() 并 沒 有 被 執 行 , 這 表 示 the_word[0] >= 128 為
FALSE。 </P>
<P><FONT COLOR="#800000">錯 誤 說 明 : </FONT></P>
<P>「 我 」 是 中 文 字 , 所 以 它 的 第 一 個 字 元 一 定 大 於 128,
而 在 「 the_word[] = "我 是 中 文 字 ";」 的 設 定 之 後 ,
the_word[0] 變 成 了 「 我 」 的 第 一 個 字 元 , 所 以 the_word[0] >=
128 應 該 為 TRUE。 </P>
<P>問 題 點 就 出 在 the_word 的 資 料 型 態 上 , 由 於 它 被 宣 告 成
char, 而 C 語 言 中 char 是 含 有 正 負 值 的 1 byte 資 料 , 其 數 值
范 圍 是 -128 到 127, 因 此 「 我 」 的 第 一 個 字 元 在 指 定 給 the_word[0]
之 後 , 便 由 >= 128 的 數 值 變 成 <= 127 的 數 值 , 所 以 if
(the_word[0] >= 128 ) 只 能 得 到 FALSE 值 了 。 </P>
<P>解 決 這 個 問 題 的 方 法 是 把 the_word 的 宣 告 改 成 : 「 unsigned
char」 型 態 , 使 其 數 值 范 圍 變 成 0 到 255, 這 樣 子 在 「 the_word[]
= "我 是 中 文 字 ";」 的 設 定 之 後 , 就 不 至 於 有 數 值
被 強 制 轉 變 的 現 象 。 </P>
<P><FONT COLOR="#800000">不 同 型 別 運 算 的 錯 誤 避 免 之 道 : </FONT></P>
<P>以 上 所 舉 的 只 是 不 同 型 別 運 算 後 產 生 錯 誤 的 兩 個 代 表
性 的 例 子 , 欲 避 免 所 有 的 錯 誤 , 以 下 是 筆 者 的 建 議 : </P>
<UL>
<P>· 檢 查 各 種 運 算 符 號 ( + 、 - 、 × 、 ÷ 、 = 、 > 、 <
等 ) 兩 邊 的 資 料 型 別 是 否 相 同 , 若 不 同 , 則 要 先 確 定 程
式 語 言 是 如 何 處 理 這 些 運 算 符 號 的 , , 如 果 不 能 確 定 ,
先 寫 個 小 程 式 試 看 看 。 </P>
<P>· 不 要 假 設 同 一 種 運 算 符 號 在 不 同 程 式 語 言 之 間 會 有
相 同 的 處 理 結 果 , 例 如 除 號 (/)在 BASIC 及 C 語 言 中 就 有 不
同 的 處 理 方 式 。 </P>
</UL>
</UL>
<H2><A NAME="s2"></A><FONT COLOR="#0000FF">程 式 轉 彎 處 </FONT></H2>
<UL>
<P>if...else、 goto、 for 回 圈 、 while 回 圈 、 exit、 return、 break
等 指 令 讓 我 們 可 以 控 制 程 式 的 流 程 , 有 了 它 們 程 式 才 會
轉 彎 , 也 因 此 可 以 執 行 出 許 多 不 同 的 結 果 , 而 bug 也 特 別
喜 歡 躲 在 這 些 轉 彎 的 地 方 , 干 擾 程 式 的 執 行 結 果 。 </P>
</UL>
<P><B><U><FONT COLOR="#000080"><FONT SIZE=+1>goto 的 後 遺 癥 </FONT></FONT></U></B></P>
<UL>
<P>大 家 都 知 道 濫 用 goto 將 使 程 式 的 結 構 變 得 不 好 , 影 響
程 式 的 可 維 護 性 , 不 過 那 并 不 表 示 任 何 情 況 都 不 要 使 用
goto, 舉 個 例 子 來 說 , 在 以 下 的 多 層 回 圈 中 , 如 果 我 們 想
跳 出 所 有 的 回 圈 , 使 用 goto 是 最 簡 單 明 白 的 方 法 。 </P>
</UL>
<UL>
<UL>
<ADDRESS><FONT COLOR="#000080">For i = 1 to M </FONT></ADDRESS>
<UL>
<ADDRESS><FONT COLOR="#000080">For k = 1 to N </FONT></ADDRESS>
<UL>
<ADDRESS><FONT COLOR="#000080">...</FONT></ADDRESS>
<ADDRESS><FONT COLOR="#000080">If cond Then goto outside </FONT></ADDRESS>
</UL>
<ADDRESS><FONT COLOR="#000080">Next </FONT></ADDRESS>
</UL>
<ADDRESS><FONT COLOR="#000080">Next </FONT></ADDRESS>
<ADDRESS><FONT COLOR="#000080">outside: </FONT></ADDRESS>
</UL>
<P>其 實 goto 與 return、 exit、 break、 continue 等 指 令 在 本 質 上
并 沒 有 差 別 , 它 們 都 會 跳 過 一 段 程 式 , 雖 然 我 們 以 goto
作 為 討 論 的 標 題 , 但 實 際 上 所 要 談 的 是 「 跳 過 一 段 程 Α
可 能 衍 生 的 後 遺 癥 」 。 </P>
<P>假 設 原 本 有 一 個 副 程 式 , 架 構 上 大 致 是 : </P>
<UL>
<ADDRESS><FONT COLOR="#000080">// C 程 式 </FONT></ADDRESS>
<ADDRESS><FONT COLOR="#000080">SubX () </FONT></ADDRESS>
<ADDRESS><FONT COLOR="#000080">{</FONT></ADDRESS>
<UL>
<ADDRESS><FONT COLOR="#000080">fp = fopen( somefile, "r"); </FONT></ADDRESS>
<ADDRESS><FONT COLOR="#000080">... </FONT></ADDRESS>
<ADDRESS><FONT COLOR="#000080">... </FONT></ADDRESS>
<ADDRESS><FONT COLOR="#000080">... </FONT></ADDRESS>
<ADDRESS><FONT COLOR="#000080">fclose( fp ); </FONT></ADDRESS>
</UL>
<ADDRESS><FONT COLOR="#000080">}</FONT></ADDRESS>
</UL>
<P>這 樣 的 副 程 式 很 不 錯 , 總 會 在 離 開 前 把 打 開 的 檔 案 關
掉 , 後 來 我 們 修 改 程 式 讓 它 在 某 種 狀 況 之 下 直 接 跳 離 副
程 式 , 所 以 加 了 一 行 判 斷 式 : </P>
<UL>
<P><FONT COLOR="#000080">if ( condition ) return;</FONT></P>
</UL>
<P>這 個 判 斷 式 當 然 沒 錯 , 但 我 們 忘 了 在 return 之 前 「 關 檔
」 了 。 </P>
<P>前 面 這 個 例 子 是 個 簡 化 版 , fclose( fp ) 就 在 眼 前 , 所 以
很 容 易 看 到 這 樣 的 錯 誤 , 但 實 際 上 一 個 副 程 式 可 能 多 達
數 頁 , 在 我 們 加 上 跳 出 副 程 式 的 判 斷 式 時 , 通 常 不 會 看
到 fclose( fp ), 加 上 您 可 能 急 著 把 程 式 跑 出 來 , 根 本 就 忘
了 關 檔 那 一 回 事 了 。 </P>
<P>而 更 糟 的 是 , 忘 了 關 檔 的 錯 誤 并 不 會 馬 上 顯 現 出 來 ,
它 只 會 讓 程 式 的 可 開 檔 案 數 越 來 越 少 , 但 程 式 還 是 可 以
正 常 執 行 , 這 樣 的 錯 誤 必 須 在 不 退 掉 程 式 之 下 連 續 的 測
試 才 會 發 現 , 而 絕 大 多 的 人 總 以 為 測 過 兩 三 次 就 OK 了 ,
於 是 這 個 bug 就 一 直 躲 藏 到 系 統 整 合 , 甚 至 軟 體 交 付 到 客
戶 的 手 上 才 被 發 現 。 </P>
<P>除 了 「 開 、 關 檔 」 有 配 對 執 行 的 關 系 之 外 , 「 記 憶 體
的 配 置 、 釋 放 」 、 「 系 統 資 源 的 配 置 、 釋 放 」 等 也 有 相
似 的 性 質 , 在 「 跳 過 一 段 程 式 」 之 後 , 宜 防 只 執 行 了 「
頭 」 ( 例 如 開 檔 ) , 而 跳 過 「 尾 」 ( 例 如 關 檔 ) 的 現 象
。 </P>
</UL>
<P><B><U><FONT COLOR="#000080"><FONT SIZE=+1>無 窮 回 圈 </FONT></FONT></U></B></P>
<UL>
<P>當 我 們 想 重 復 做 某 一 件 事 , 少 不 了 回 圈 的 幫 忙 , 但 如
果 控 制 不 良 , 可 能 造 成 程 式 一 直 在 回 圈 中 打 轉 , 進 入 所
謂 的 「 無 窮 回 圈 」 。 一 旦 進 入 無 窮 回 圈 , 程 式 就 像 死 當
一 樣 , 所 以 這 個 問 題 通 常 在 程 式 測 試 的 階 段 就 會 被 發 現
。 </P>
<P>就 程 式 的 撰 寫 習 慣 上 , 有 些 小 動 作 可 以 輕 易 地 避 免 無
窮 回 圈 的 發 生 , 舉 個 例 子 來 說 : </P>
<UL>
<ADDRESS><FONT COLOR="#000080">Dim i as Integer </FONT></ADDRESS>
<ADDRESS><FONT COLOR="#000080">i = 1 </FONT></ADDRESS>
<ADDRESS><FONT COLOR="#000080">While i <> 10 </FONT></ADDRESS>
<UL>
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -