溢位問題本質
定長整數型別 (byte, short, int, long 等) 有固定值域。運算結果超出範圍即發生溢位。
byte b = 255;
b = b + 1; // 理論 256,實際 0 (回繞)
兩種控制層級
| 層級 | 方式 | 範圍 | 優先順序 |
| 專案層級 | 編譯器選項 /checked+ 或 /checked- | 整個組件 | 最低 (預設值) |
| 區塊/運算式層級 | checked / unchecked 關鍵字 | 指定區塊或單一運算式 | 最高 (覆蓋專案設定) |
checked / unchecked 關鍵字用法
區塊形式
checked {
int a = int.MaxValue;
int b = a + 1; // 拋出 OverflowException
}
unchecked {
int c = int.MaxValue + 1; // 截斷回繞,c = -2147483648
}
運算式形式
int x = checked(int.MaxValue + 1); // 拋出
int y = unchecked(int.MaxValue + 1); // 截斷
受影響運算
- 一元運算子:
++, --, - (負號) —— 僅當運算元為整數
- 二元運算子:
+, -, *, / —— 兩運算元皆為整數
- 顯式數值轉換:
(byte)largeInt, (int)largeLong
不受影響:浮點數運算、decimal (自帶溢位檢查)、邏輯運算、位移運算。
常數運算式 vs 非常數運算式
| 類型 | 預設行為 | checked 內文 | unchecked 內文 |
| 常數運算式 (編譯期可計算) | 編譯錯誤 (溢位視為錯誤) | 編譯錯誤 | 允許,截斷結果 |
| 非常數運算式 (執行期計算) | 依專案設定 (預設 unchecked) | 執行期拋出 OverflowException | 截斷,不拋出 |
const int MAX = int.MaxValue;
// 常數運算式
int c1 = MAX + 1; // CS0220: 編譯錯誤 (常數溢位)
int c2 = checked(MAX + 1); // CS0220: 編譯錯誤
int c3 = unchecked(MAX + 1); // 通過,c3 = -2147483648
// 非常數運算式
int v = GetValue(); // 執行期才知值
int r1 = v + 1; // 預設 unchecked:截斷
int r2 = checked(v + 1); // 執行期可能拋出
階乘範例:溢位檢測實戰
long Factorial(int n)
{
long result = 1;
for (int i = 2; i <= n; i++)
{
checked { result *= i; } // 單步檢測
}
return result;
}
// 呼叫
try { Console.WriteLine(Factorial(25)); } // 25! > long.MaxValue → OverflowException
catch (OverflowException) { Console.WriteLine("溢位!"); }
方法呼叫邊界:checked 不跨越方法
int Multiply(int x, int y) => x * y; // 此處無 checked
// 呼叫端加 checked 無效!
int r = checked(Multiply(1000000, 1000000)); // 不會拋出,Multiply 內部 unchecked
// 正確做法:在 Multiply 方法內部加 checked,或回傳 checked 運算式
最佳實踐建議