checked 和 unchecked 语句
控制相应块中的整型数算术运算和转换的溢出检查,checked 为检查,unchecked 为不检查。
checked 和 unchecked 运算符
控制相应表达式中的整型数算术运算和转换的溢出检查,checked 为检查,unchecked 为不检查。
checked 和 unchecked 语句与运算符仅仅是作用区域不同,效果一致。
溢出检查与不检查
用最简单的 byte 类型描述两者的区别。checked 可以在 unchecked 代码段或表达式(溢出不检查)中指定某一部分强制检查。
备注 |
---|
C# 的 byte 没有加法(既没有 + 运算符,也没有 add 方法)。下例中只能强制转换加法结果,否则就被作为 int 加法,出现警告。byte b = a + z3; 或者 byte b = ( byte ) a + ( byte ) z3; 均警告 CS0266:无法将类型“int”隐式转换为“byte” |
byte a = byte . MaxValue;
byte z3 = 3;
checked
{
try
{
byte b = ( byte )( a + z3 );
Console . WriteLine ( b );
}
catch ( OverflowException ych溢出 )
{
Console . WriteLine ( ych溢出 . Message );
}
}
上例指定的该代码块溢出检查。由于 byte 无法表示大于 255 的整数(255 + 3),所以得到结果:
Arithmetic operation resulted in an overflow.
那么溢出不检查呢?
byte a = byte . MaxValue;
byte z3 = 3;
unchecked
{
byte b = ( byte )( a + z3 );
Console . WriteLine ( b );
}
上例指定该代码块不检查溢出。于是结果很奇怪:2。
上例中的结果来自下式(2 进制的):
$$ 11111111 + 00000011 = (1)00000010(括号内抛弃) $$
unchecked 强制进行运算,但抛弃溢出目标类型的二进制位,只返回目标范围内的二进制位。checked 只会引发异常,或顺利运行。
是否检查溢出的用途
以下操作受 checked 和 unchecked 的操作符和语句建立的溢出检查上下文的影响:
- 当操作数为整型或枚举类型时,预定义的 ++ 和 -- 操作符。
- 当操作数为整型时,预定义的一元操作符 -。
- 当两个操作数都是整型或枚举类型时,预定义的加减乘除二元操作符。
- 从一个整型或枚举类型到另一个整型或枚举类型,或从浮点型或双精度型到整型或枚举类型的显式数值转换。
当上述操作之一产生的结果太大而无法在目标类型中表示时,执行该操作的上下文控制结果行为:
- 在 checked 上下文中,如果操作是常量表达式,则会发生编译时错误。否则,当在运行时执行该操作时,会出现 System . OverflowException。
在 unchecked 上下文中,通过丢弃不适合目标类型的任何高阶位来截断结果。
备注 对于非常量表达式(在运行时求值的表达式),没有处于任何 checked 或 unchecked 块或函数中,默认的溢出检查上下文是不检查的,除非外部因素(如编译器开关和执行环境配置)要求检查。 对于常量表达式(可以在编译时完全求值的表达式),总是默认检查溢出上下文。除非将常量表达式显式地放置在未检查的上下文中,否则在表达式的编译时求值期间发生的溢出总是会导致编译时错误。 - 匿名函数不受发生匿名函数的 checked 或 unchecked 上下文的影响。
下例三个函数,三个结果不同哦:
static readonly int x = 1000000;
static readonly int y = 1000000;
static int c ( ) => checked(x * y); // 引发 OverflowException
static int u ( ) => unchecked(x * y); // 返回 -7,273,379,968
static int m ( ) => x * y; // 引发异常或返回值(根据是否在 checked 上下文中返回结果)
checked 和 unchecked 运算符只会影响文本包含在“(”和“)”标记中的运算的溢出检查上下文。 运算符对函数成员没有影响,这些函数成员是在对所含表达式进行求值后被调用的。
以下代码中:
{
static int Multiply(int x, int y) => x * y;
static int F() => checked(Multiply(1000000, 1000000));
}
在 F 中使用 checked 不会影响 Multiply 中 x y 的求值,因此 x y 将在默认的溢出检查上下文中求值。
方便之处
当以十六进制表示法编写带符号整型类型的常量时,unchecked 运算符很方便。
{
public const int AllBits = unchecked ( ( int ) 0xFFFFFFFF );
public const int HighBit = unchecked ( ( int ) 0x80000000 );
}
上述两个十六进制常量的类型都是 uint。 由于常量超出了 int 的范围,如果没有 unchecked 运算符,将常量强制转换为 int 会产生编译时错误。
注释: |
---|
checked 和 unchecked 运算符和语句允许程序员控制某些数值计算的某些方面。 但是,某些数值运算符的行为取决于其操作数的数据类型。 例如,两个小数相乘总是会在溢出时出现异常,即使在显式未检查的结构中也是如此。 同样,即使在显式检查的结构中,两个浮点数相乘也不会出现溢出异常。 此外,其他运算符永远不会受到检查模式的影响,无论是默认还是显式。永远不要对 float 和 double 进行 checked 和 unchecked。 |
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。