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 ...
随机推荐
- ThinkPHP使用PHPExcel实现Excel数据导入导出完整实例
这篇文章主要介绍了ThinkPHP使用PHPExcel实现Excel数据导入导出,非常实用的功能,需要的朋友可以参考下 本文所述实例是使用在Thinkphp的开发框架上,要是使用在其他框架也是同样的方 ...
- java - day06 - arraycopy
package day05; import java.util.Arrays; import java.util.Random; /* * 附:如果需要使用引用类,如Random类的方法, * 需要新 ...
- CentOS统的7个运行级别的含义
原文: http://blog.csdn.net/liansehai/article/details/45370965 CentOS系统有7个运行级别(runlevel) 运行级别就是操作系统当前正在 ...
- linux 命令之 ping
ping命令主要用于检測主机的连通性. 语法: ping [-dfnqrRv] [-c <完毕次数>] [-i <间隔秒数>] [-I <网络接口>] [-l &l ...
- mysql命令 SHOW TABLE STATUS LIKE '%city%'; 查看表的状态可以查看表的创建时间
show status like '%handler_read_key%'; #走索引的命令的数量. #查看存储引擎 mysql> show variables like '%engine%'; ...
- ACM Computer Factory - poj 3436 (最大流)
Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 5949 Accepted: 2053 Special Judge ...
- 【Mac安装,ATX基于uiautomator2】之安装步骤
Mac系统下安装uiaotumator2: 参考网址:<uiautomator2>以及参考github官方文档 注意:下面有坑,如果你没有下面的问题请直接跳转到 1.安装uiaotumat ...
- 一种安全云存储方案设计(下)——基于Lucene的云端搜索与密文基础上的模糊查询
一种安全的云存储方案设计(未完整理中) 一篇老文了,现在看看错漏颇多,提到的一些技术已经跟不上了.仅对部分内容重新做了一些修正,增加了一些机器学习的内容,然并卵. 这几年来,云产品层出不穷,但其安全性 ...
- staticmethod classmethod修饰符
一.staticmethod(function) Return a static method for function.A static method does not receive an imp ...
- springmvc 生命周期
1A)客户端发出http请求,只要请求形式符合web.xml 文件中配置的*.action的话,就由DispatcherServlet 来处理. 1B)DispatcherServlet再将http请 ...