C# 抛出 OverflowException 的时机与 checked、unchecked 关键字

C# 抛出 OverflowException 的时机与 checked、unchecked 关键字


为了测试 bauann 大所说的:在 Windows7 /x64 平台上,VS2008 的 Debug Mode 是不是怪怪的?,不料挖出了自己观念不够清楚的地方,关于 C# 侦测 OverflowException 的条件…。

直接看底下简化的程序:
{
    int maxInt = Int32.MaxValue;
    int two = 2;
    int result = maxInt * two;

    Console.WriteLine("{0} * {1} = {2}rn>>>NG!rnOverflowException 咧...?",
        maxInt,
        two,
        result);
}
catch (Exception e)
{
    Console.WriteLine("发生例外状况:{0}", e.Message);
}

Console.ReadKey(true);


将变量 maxInt 指定为整数的最大值 (2,147,483,647),如果再乘以 2,估计将发生溢位而抛出例外,但实际上执行起来不是这样…正当狐疑之际,噗浪上 bauann 大响应说同样的逻辑在 VB 会丢出例外,而且还提供了一个连结,是一篇外国人写的 C# 文章,其中有一段叙述著:
Oddly enough, by default, C# does not throw an exception for numerical overflows or underflows. To have C# check, you must use the "checked"  keyword, or configure your project to check all arithmetic.

奇怪的是默认情况下 C# 不会抛出数值溢位或反向溢位。要让 C# 检查,你必须使用 "checked" 关键字,或设置你的项目检查所有运算。

有了第一个说法,接着查阅 MSDN 看看是否属实,发现以上叙述不够完整 (我只针对字面叙述理解,不代表原作者立场),事实上是这样的,若运算式只包含常数(算子都是常数),例如在前述程序中,Int32.MaxValue 直接乘以 2,那在编译时期就会检查是否超出类型范围,若侦测到就会有编译时期溢位错误, 参考底下画面:

OverflowException_Complie_Time

另一个状况正如一开始的的程序,运算式里包含变量,这种情况称之为非常数运算式 (non-constant expression),编译时期不会侦测溢位,默认情况下,执行时期也不会检查,要强制执行检查最直接的方式是用 checked 关键字,例如修改原本程序,第 5 行加入 checked():
{
    int maxInt = Int32.MaxValue;
    int two = 2;
    int result = checked(maxInt * two);

    Console.WriteLine("{0} * {1} = {2}rn>>>NG!rnOverflowException 咧...?",
        maxInt,
        two,
        result);
}
catch (Exception e)
{
    Console.WriteLine("发生例外状况:{0}", e.Message);
}

Console.ReadKey(true);


其他还包括项目属性设定、/checked 编译器选项等方式,至于 unchecked 关键字则是用在抑止检查,假设环境已先被设置为启用溢位检查…当然保守的做法是你很确定该程序不会有 overflow 发生,这时就可以用 unchecked 去抑止,以期改善一点性能。这些部分由于做法很简单,想了解的人可以自行参考相关主题连结,不再浪费篇幅介绍了。

题外话,已经不只一次觉得中文版的 MSDN Library 翻译得实在不怎么样,更新日期也比较慢,像这次怎么看怎么不懂,有一部分原因是关键地方交代不清楚,还要切换到英文版去看(英文版已更新内容,有比较清楚些),个人英文能力又不上不了台面,还是反复参考 checked、unchecked 两篇说明,并且对照范例才真正了解,有时候觉得虽然有自己母语版本的说明文档是很亲切没错,却还是得依赖原文说明文档才能了解真正意思,还真够无言的…。

【2010/1/13 补充】

刚刚逛点部落,发现 alonstar 写过一篇文章,里面有使用项目属性设定方式启用执行时期溢位检查的图文说明,有需要的人不妨过去看看:
[C#]阅读笔记:indexer, keyword:checked, operator