zoukankan      html  css  js  c++  java
  • C# checked和unchecked详解

    C# checked和unchecked详解

    1、对基元类型执行的许多算术运算都可能造成溢出,有如下代码:

    1

    2

    Byte b=100;

    b=(Byte)(b+200);

    简单的解读上面的代码:

    第一步,将所有的操作数都扩大至32位或者64位(根据操作系统的位数决定)。所以b和200(这两个值都不超过32位),首先转换成32位(假设当前操作系统是32位),然后加到一起。结果就是一个32位值(十进制300或者十六进制12C)。注意此时的值为一个32位的操作数,必须转型为一个byte。C#不会隐式地执行这个转型操作,这正是第二行代码需要强制转换为Byte的原因.如果不把结果值强制转换为Byte,代码如下:

    byte b = 100;
    b = b +300;

    如果将值强行转换为Byte,那么还会出现一个问题,就是值溢出的问题,Byte只能表示0~255范围的值,所以300超出了Byte的范围,值就溢出了.不同的语言以不同的方式处理溢出,C和C++不视溢出为错误,并允许值回滚.应用程序将若无其事的运行.相反,Microsoft Visual Basic总将溢出视为错误,并会在检测到溢出时抛出一个错误.

    而CLR提供了一些特殊的IL指令,允许编译器选择它认为最正确的行为。CLR有一个add指令,将作用是将两个值加到一起,但不执行溢出检查。CLR还有一个add.ovf的指令,作用是将两个值加到一起,但会在抛出异常时抛出一个System.OverflowException异常。除了用于加法运算的这两个IL指令外,CLR还为减、乘和数据转换提供了类似的IL指令,分别是sub/sub.ovf,sub/sub.ovf和conv/conv.ovf。

    也就是说C#允许程序员自己决定如何处理溢出,溢出检查默认是关闭的。因为这样能保证代码的运行效率,但是开发人员必须保证不会发生溢出,或者他们的代码能预见到这些溢出.

    2、控制溢出的方法

    第一种:打开/checked编译器开关.这个开关指示编译器在生成代码时,使用加、减、乘、除和转换指令的溢出检查版本也就是带.vof的版本,这样,在生成代码时,就会检查代码是否溢出.

    下面是/checked编译器开关的打开方式:

    第二种:就是用checked和unchecked关键字来控制溢出的检查与否,这体现的C#溢出检查的灵活性.

    下面是一个在/checked编译器开关打开的情况下,使用unchecked关键字强制不检查unchecked包裹的代码的溢出问题,代码如下:

    UInt32 a = unchecked((UInt32)(-1));
    Console.WriteLine(a); //一个很大的数

    下面在/checked编译器开关关闭的情况下,使用checked关键字检查其包裹的代码的溢出问题,代码如下:

    byte b = 100;
    b =checked((Byte)(b +300)); //溢出错误
    Console.WriteLine(b);

    3、checked和unchecked语句

    除了上面的checked和unchecked关键字外,checked和unchecked还可以是语句,它们造成一个块中的表达式就进行/不进行溢出检查.代码如下:

    checked
    {
         byte b = 100;
         b += 200;//在checked语句块内,可以直接使用+=操作符,编译器自动会把值转换为byte,前提200必须在byte范围内
         Console.WriteLine(b);
    }
    

    4、关于基元类型进行算术操作产生溢出的建议

    a、在应用程序能够容忍checked运算造成的性能损失的情况下,尽可能的打开/checked编译器开关,保证程序的正常运行

    b、尽量使用有符号整数(Int32,Int64),少使用无符号整数(UInt32,UInt64)

    c、将不希望发生overflowException的代码块作用于checked关键字下,并捕获overflowException,并即时从异常中恢复.

    d、c的反例,unchecked的用法.

  • 相关阅读:
    经典矩阵dp寻找递增最大长度
    有符号char转无符号short
    正则表达式学习之grep,sed和awk
    Git学习总结
    Linux下的压缩及归档
    bash脚本编程学习笔记(二)
    bash脚本编程学习笔记(一)
    Linux磁盘及文件系统(三)Linux文件系统
    Linux磁盘及文件系统(二)Linux下磁盘命名和分区
    Linux磁盘及文件系统(一)
  • 原文地址:https://www.cnblogs.com/grj001/p/12224832.html
Copyright © 2011-2022 走看看