赞
踩
本节课重点说一下关于数据范围溢出的问题。我将会为大家介绍两个关键字 checked 和 unchecked 。请注意下图1.是否是你想要的结果?
当在变量 i 的值是 2147483647 时,在其基础上 +1 。结果为:-2147483648 !是负数!是 int 类型的最小值!你是否希望出现这个结果,如果你认为这是个意外,不应该出现,那么你要学习 checked 关键字!如果你觉得这很正常,而且你需要得到的就是这个计算结果,那你需要了解 unchecked 关键字!
在块语句或表达式的前面,添加 checked 关键字,使所使其成为 checked context(检查上下文)状态。这意味着在运行时检查某些算术操作(包括强制类型转换)是否存在范围溢出。如果在检查的上下文中将值强制转换为整数类型,并且值过高或过低而无法匹配,则会发生错误—代码将抛出 System.OverflowException 异常。这时可使用 try…catch…捕获后进行处理。如下例所示:
由图2.示例我们可以看到,当我们在变量 i 最大值(用 int.MaxValue 属性获得)的基础上进行了 +1 操作,导致溢出!这时就会被 checked 检查到,抛出 OverflowException 异常,捕获后用户可以自行处理。但一定要注意,在执行到 i=i+1 抛出异常后,直接执行 catch 块语句,不会再执行 try 块语句了。未来讲 try...catch...时细说。所以第16行根本没有执行。
有小伙伴会觉得,这个异常抛的很正常啊,难道 checked 真的起作用啦?下面截图3.显示未添加 checked 机制的结果。加法运算符完美的进行了运算,精确的将二进制结果显示出来。
图3.展示的结果说明编译器未发现错误(本身也确实没有错误),所以正确执行,得出了编译器认为的正确结果!为啥 最大值+1=最小值 ?计算机会鄙视你,问你为什么当初把它设计为二进制的。
既然不添加 checked 就不会检查溢出状态,为啥还要有 unchecked ?
虽然在我们的城市里,充满了阳光与希望。当发生问题后,警察♀️叔叔、消防队员会第一时间出现帮助我们解决问题。但就像硬币有两个面一样,依然会有邪恶势力的存在。unchecked 就是他们的保护伞。一般情况下,unchecked 会嵌套在 checked 中,当要求所有人都遵纪守法,但个别人却需要获得豁免权时,就要对这少部分人启用 unchecked 。如下示例:
static void Main(string[] args){ #pragma warning disable CS0219 int x=0; int y=0; try { checked { unchecked { x=int.MaxValue+1; Console.WriteLine(x); } } } catch(OverflowException) { Console.WriteLine("我们抓住了溢出!"); }}
如图4.所示,unchecked { .. } 代码块中的所有表达式与变量均不会收到“溢出”检查。无论是否溢出,都不会抛出异常。虽然在外层已经设置了 checked 关键字,但显然 unchecked 不买账,强制取消了 checked 设置的溢出检查机制。所以 checked 代码块内的变量 x 经计算后,虽然溢出,但不会抛出。
但如下图5.所示,不在 unchecked 内的变量 y 如果溢出,则抛出异常:
OK,关于 checked 与 unchecked 的关系我们通过图5.已经一目了然。checked 就像警察,维护整个社会秩序,而 unchecked 就像黑涩会,虽然与警察对着干,但如果这个社会没有警察,也就没有了所谓的黑涩会。
除了检查语句块中计算是否存在溢出外,还可以应用在表达式中,如下所示:
int result = checked(a + b) + c;
如图6.所示,checked 还可以应用在表达式中,便捷的检查溢出情况。
总的来说,checked context 机制的使用频率还是比较低的。很多情况下,编译器直接报错,不予编译,而不会抛出异常。
但在某些情况下,如大规模数学运算中,大数值会频繁使用,为确保意外情况的发生,最好还是使用 checked 机制及时检查其中可能会发生的溢出问题。严谨,是每个程序员必须要崇拜的词汇!
请注意,检查成本会使单个整数操作慢上几倍。它对应用程序的整体影响会更小,因为程序不会把它们的全部时间都花在执行算术上,但代价可能仍然不小。当然,对于任何性能问题,您都应该度量实际影响。您可能会发现,性能成本是一个可以接受的价格,以保证您将发现意外溢出。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。