checked 和 unchecked 基元类型操作
对基元类型执行的许多算术运算都可能造成溢出:
Byte b = ;
b = (Byte) (b + ); // b 现在包含 44(或者十六进制值 2C)
重要提示:执行上述算术运算时,第一步要求所有操作数都扩大为 32 位值(或者 64 位值,如果任何操作数需要超过 32 位来表示的话)。所以, b 和 200(这两个值都不超过 32 位) 首先转换成 32 位值,然后加到一起。结果是一个 32 位值(十进制 300,或十六进制 12C)。该值在存回变量 b 之前,必须转型为一个 Byte。
C#不会隐式执行这个转型操作,这正是第二行代码需要强制转换为 Byte 的原因。
在大多数编程情形中,这种静悄悄发生的溢出是我们不希望的。如果没有检测到这种溢出,会导致应用程序行为失常。但在极少数编程情形中,比如计算一个哈希值或者校验和,这种溢出不仅是可以接受的,还是我们希望的。
不同语言以不同方式处理溢出。 C 和 C++不将溢出视为错误,并允许值回滚( wrap) 39;应用程序将“若无其事”地运行。相反, Microsoft Visual Basic 总是将溢出视为错误,并会在检测到溢出时抛出一个异常。
CLR 提供了一些特殊的 IL 指令,允许编译器选择它认为最恰当的行为。 CLR 有一个 add 指令,作用是将两个值加到一起,但不执行溢出检查。 CLR 还有一个 add.ovf 指令,作用也是将两个值加到一起,但会在发生溢出时抛出一个 System.OverflowException 异常。除了用于加法运算的这两个 IL 指令, CLR 还为减、乘和数据转换提供了类似的 IL 指令,分别是 sub/sub.ovf, mul/mul.ovf 和 conv/conv.ovf。
C#允许程序员自己决定如何处理溢出。溢出检查默认是关闭的。也就是说,编译器在生成 IL 代码时,会自动使用加、减、乘以及转换指令的不含溢出检查的版本。这样的结果是代码能够更快地运行——但是,开发人员必须保证不会发生溢出,或者他们的代码能预见到这些溢出。
让 C#编译器控制溢出的一个办法是使用 /checked+编译器开关。这个开关指示编译器在生成代码时,使用加、减、乘和转换指令的溢出检查版本。这样生成的代码在执行时会稍慢一些,因为 CLR 会检查这些运算,判断是否会发生溢出。如果发生溢出, CLR 会抛出一个 OverflowException 异常。
除了全局性地打开或关闭溢出检查,程序员还可在代码的特定区域控制溢出检查。 C#通过提供 checked和 unchecked 操作符来实现这种灵活性。 下面是一个使用了 unchecked 操作符的例子:
UInt32 invalid = unchecked((UInt32) (-)); // OK
下例则使用了 checked 操作符:
Byte b = ;
b = checked((Byte) (b + )); // 抛出 OverflowException 异常
在这个例子中, b 和 200 首先转换成 32 位值,然后加到一起,结果是 300。然后,因为显式转型的存在, 300 被转换成一个 Byte,这造成一个OverflowException 异常。如果 Byte 是在 checked 操作符的外部转
型的,则不会发生异常:
b = (Byte) checked(b + ); // b 包含 44;不会抛出 OverflowException 异常
除了 checked 和 unchecked 操作符, C#还支持 checked 和 unchecked 语句,它们造成一个块中的所有表达式都进行或不进行溢出检查:
checked { // 开始一个 checked 块
Byte b = ;
b = (Byte) (b + ); // 该表达式会进行溢出检查
} // 结束一个 checked
事实上,如果使用了一个 checked 语句块,就可以将+=操作符用于 Byte,从而稍微简化一下代码:
checked { // 开始一个 checked 块
Byte b = ;
b += ; // 该表达式会进行溢出检查
}
重要提示:由于 checked 操作符和 checked 语句唯一的作用就是决定生成哪一个版本的加、减、乘和数据转换 IL 指令,所以在一个 checked 操作符或者语句中调用一个方法,不会对该方法造成任何影响。
重要提示:
System.Decimal 类型是一个非常特殊的类型。虽然许多编程语言(包括 C#和 Visual Basic) 都将 Decimal视为一个基元类型,但 CLR 则不然。这意味着 CLR 没有相应的 IL 指令来决定如何处理一个 Decimal 值。在.NETFramework SDK 文档中查看 Decimal 类型可以看出,它提供了一系列 public static 方法,包括 Add, Subtract,Multiply, Divide 等。除此之外, Decimal 类型还为+, -, *, /等提供了操作符重载方法。
编译使用了 Decimal 值的程序时,编译器会生成代码来调用 Decimal 的成员,并通过这些成员来执行实际的运算。这意味着 Decimal 值的处理速度慢于 CLR 基元类型的值的处理速度。另外,由于没有相应的IL 指令来处理 Decimal 值,所以 checked 和 unchecked 操作符、 语句以及编译器开关都失去了效用。 如果对
Decimal 值执行的运算是不安全的,肯定会抛出一个 OverflowException 异常。
类似地, System.Numerics.BigInteger 类型也在内部使用一个 UInt32 数组来表示一个任意大的整数,它的值没有上限和下限。因此,对 BigInteger 执行的运算永远不会造成 OverflowException 异常。然而,如果值 太 大 , 而 且 没 有 足 够 多 的 内 存 来 改 变 数 组 的 大 小 , 对 BigInteger 的 运 算 可 能 抛 出 一 个OutOfMemoryException 异常。
checked 和 unchecked 基元类型操作的更多相关文章
- 《CLR via C#》读书笔记--基元类型、引用类型和值类型
编程语言的基元类型 编译器直接支持的数据类型称为基元类型.基元类型直接映射到Framework类库中存在的类型.例如:C#中的int直接映射到System.Int32类型.下表给出了C#基元类型与对应 ...
- 【C#进阶系列】05 基元类型、引用类型和值类型
基元类型和FCL类型 FCL类型就是指Int32这种类型,这是CLR支持的类型. 而基元类型就是指int这种类型,这是C#编译器支持的,实际上在编译后,还是会被转为Int32类型. 而且学过C的朋友 ...
- 重温CLR(四)基元类型、引用类型、值类型
编程语言的基元类型 编译器直接支持的数据类型称为基元类型(primitive type).基元类型直接映射到framework类型(fcl)中存在的类型. 下表列出fcl类型 从另一个角度,可以认为C ...
- 读经典——《CLR via C#》(Jeffrey Richter著) 笔记_基元类型(三)
[checked 和 unchecked 基元类型操作] 1.第一种使用方式 UInt32 invalid = )); //OK,不会抛异常 Byte b = ; b = ));//抛出Overflo ...
- .net 基元类型,引用类型和值类型
基元类型(primitive type): 编译器直接支持的数据类型称为基元类型(primitive type). string 与 String: 由于C#中的string (一个关键字)直接映射到 ...
- System.Buffer 以字节数组(Byte[])操作基元类型数据
1. Buffer.ByteLength:计算基元类型数组累计有多少字节组成. 该方法结果等于"基元类型字节长度 * 数组长度" , , }; , , }; , , }; Cons ...
- 《CLR via C#》读书笔记(5)基元类型、引用类型和值类型
5.1 基元类型 编译器直接支持的数据类型称为基元类型(primitive type). 以下4行到吗生成完全相同的IL int a = 0; //最方便的语法 System.Int32 b = 0; ...
- 【CLR Via C#】第5章 基元类型、引用类型、值类型
第二遍看这本书,决定记录一下加深印象. 1,基元类型 什么事基元类型?基元类型是直接映射到FrameWork类库(FCL)中存在的类型,编译器直接支持的数据类型.比如int直接映射到System.In ...
- [CLR via C#]5.1 基元类型
原文:[CLR via C#]5.1 基元类型 某些数据类在开发中非常常用,以至于许多编译器允许代码已简化的语法来操作它们.例如可以使用以下语法来分配一个整数: System.Int32 a = ne ...
随机推荐
- 【Akka】在并发程序中使用Future
引言 在Akka中, 一个Future是用来获取某个并发操作的结果的数据结构.这个操作一般是由Actor运行或由Dispatcher直接运行的. 这个结果能够以同步(堵塞)或异步(非堵塞)的方式訪问. ...
- 版本控制器-VSS和SVN区别
SVN 默认的工作方式和VSS不同, VSS是[锁定-修改-解锁],VSS是一个人在改的时候必须以独占的方式签出文件,导致其他人不能够修改.用VSS经常要问同事:"改完没,签入一下" ...
- 142. O(1) Check Power of 2【easy】
142. O(1) Check Power of 2[easy] Using O(1) time to check whether an integer n is a power of 2. Have ...
- 转载-android studio 各种问题
android studio 各种问题 1.dexDebug ExecException finished with non-zero exit value 2 全bug日志如下: (Error:Ex ...
- iOS 学习笔记七 【博爱手把手教你使用2016年gitHub Mac客户端】
iOS 学习笔记七 [博爱手把手教你使用gitHub客户端] 第一步:首先下载git客户端 链接:https://desktop.github.com 第二步:fork 大神的代码[这里以我的代码为例 ...
- js模板引擎artTemplate快速上手
腾讯的artTemplate 1,编写模板 (采用script标签并带有属性id和type="text/html") <script id="test" ...
- cookie做订单
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- rem的使用方法
首先写入一下代码 <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" cont ...
- hdu 4587(割点的应用)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4587 思路:题目的意思很简单,就是删除任意2个节点以及关联的边,求图的最大连通分量数.我们知道删除割点 ...
- poj 2195(KM求最小权匹配)
题目链接:http://poj.org/problem?id=2195 思路:我们都知道KM使用来求最大权匹配的,但如果要求最小权匹配,只需把图中的权值改为负值,求一次KM,然后权值和取反即可. ht ...