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的用法.

  • 相关阅读:
    Matlab 绘制三维立体图(以地质异常体为例)
    Azure DevOps的variable group实现array和hashtable参数的传递
    Azure DevOps 利用rest api设置variable group
    Azure AADSTS7000215 其中一种问题的解决
    Power BI 实现实时更新Streaming Dataset
    AAD Service Principal获取azure user list (Microsoft Graph API)
    Matlab 沿三维任意方向切割CT图的仿真计算
    Azure Powershell script检测登陆并部署ARM Template
    Azure KeyVault设置策略和自动化添加secrets键值对
    Azure登陆的两种常见方式(user 和 service principal登陆)
  • 原文地址:https://www.cnblogs.com/grj001/p/12224832.html
Copyright © 2011-2022 走看看