Checked和Unchecked操作符似乎不起作用

时间:2010-06-15 19:30:19

标签: c#

1)UNCHECKED运算符仅在UNCHECKED上下文中的表达式使用显式强制转换(例如byte b1=unchecked((byte)2000);)并且隐式转换为特定类型时才有效吗?我假设这是因为以下表达式抛出编译时错误:

byte b1=unchecked(2000); //compile time error

2)a)CHECKEDUNCHECKED运算符只有在表达式或转换的结果值为integer类型时才有效吗?我假设这是因为在第一个示例中(其中double类型转换为integer类型)CHECKED运算符按预期工作:

        double m = double.MaxValue;
        b=checked((byte)m); // reports an exception

,而在第二个示例中(其中double类型正在转换为float类型)CHECKED运算符似乎不起作用。因为它没有抛出异常:

        double m = double.MaxValue;
        float f = checked((float)m); // no exception thrown

b)为什么两个运算符也不能处理结果值的类型为floating-point type的表达式?

2)下一个引用来自微软的网站:

  

unchecked关键字用于控制整数类算术运算和转换的溢出检查上下文

我不确定我是否理解unchecked((byte)(100+200));integrals共同的表达和转换究竟是什么?

谢谢

4 个答案:

答案 0 :(得分:4)

  

仅当未经检查的上下文中的表达式使用显式强制转换以及何时可以隐式转换为特定类型时,未经检查的运算符是否有效?

没有。取消选中未经检查的运算符内的所有操作,除非未经检查的运算符当然包含已检查的运算符。

  

只有当表达式或转换的结果值是整数类型时,check和unchecked运算符才有效吗?

checked和unchecked运算符只对整数类型有可观察的影响,是的。

  

为什么两个运算符也不能处理结果值的类型是浮点类型的表达式?

Double和float类型具有无穷大,负无穷大和NaN值,可用作溢出操作的结果。任何整数类型中都没有为此类“错误”情况保留的“未分配”值。 Double和float可以通过它们的值发出错误信号;整数不能。因此,如果要检测溢出,则需要能够为整数错误打开一些信号机制。

  

unchecked关键字用于控制整数类算术运算和转换的溢出检查上下文

正确。我注意到这会回答你的前两个问题。

  

我不确定我是否理解究竟有什么表达和转换,例如unchecked((byte)(100 + 200));与积分共同?

100是整数型。 200是整体类型。他们的总和是整体类型。字节是一个整数类型。表达中的所有内容都是整体类型。

  

谢谢

欢迎你。

答案 1 :(得分:2)

  1. byte b1=unchecked((byte)2000);编译正常:2000被转换为byte并且由于未经检查的上下文而没有抛出OverflowException因此将值赋给{{没有问题1}}。

    b1导致编译时错误,因为常量值2000无法转换为byte b1=unchecked(2000);值。

  2. 这就是specification所说的内容:

      

    以下操作受已检查和未检查的运算符和语句建立的溢出检查上下文的影响:

         
        
    • 当操作数是整数类型时,预定义的++和 - 一元运算符(第7.5.9节和第7.6.5节)。
    •   
    • 预定义 - 一元运算符(第7.6.2节),当操作数是整数类型时。
    •   
    • 预定义的+, - ,*和/ binary运算符(第7.7节),当两个操作数都是整数类型时。
    •   
    • 从一个整数类型到另一个整数类型,或从float或double到整数类型的显式数值转换(第6.2.1节)。
    •   

    最后几点指出,从double到float的显式转换是受溢出检查的影响,因此表达式byte将导致float f = checked((float)double.MaxValue);Infinity }将被检查并抛出byte b=checked((byte)double.MaxValue);,因为转换为整数类型。

答案 2 :(得分:1)

可能存在浮点运算不太可能溢出的假设。 (如果你想尝试它,请使用double x = double.MaxValue * double.MaxValue;)将double转换为(单个)float不会这样做,因为截断是精确的,而不是溢出。

在任何情况下,不同的指令处理浮点运算,并且在没有详细的硬件知识的情况下,我不知道信号是如何或者是否以任何方式溢出,或者如果由于某种原因而没有处理它。对于Eric Lippert(C#开发团队)来说,这是一个很好的问题,如果他碰巧读到这个。

我还假设“整数类型算术”表示整数,这将涵盖字节和整数类型之间的转换。它可能会改变转换的方向。

答案 3 :(得分:1)

溢出检查是一个非常多的运行时功能,编译器与它几乎没有关系。如果你看看Ecma 335,它可能会有所帮助,这是一个描述IL操作码可用的标准文档。有4组操作码具有允许溢出检查的形式:

  • add vs add.ovf,添加两个数字
  • sub vs sub.ovf,减去两个数字
  • mul vs mul.ovf,乘以两个数字
  • conv vs conv.ovf,转换1,2,4或8字节整数

所有这些都存在于签名的无符号变体中。前3个显然与相应的运算符直接相关。转换操作码由源代码中的强制转换生成。

C#编译器在编译由checked关键字括起来的代码时所做的一切就是在发出IL时切换到这些操作码的.ovf种类。实际生成执行溢出检查的机器代码是JIT编译器的工作。

从中可以看出一些行为:

  • checked关键字对文字没有影响,它们的值由编译器直接评估并且不产生IL。这可以在技术上完成,但编译器目前不这样做。今天不太好但太破碎无法修复。
  • 转换为double的conv.r4操作码没有.ovf版本,只有整数转换才有它们。

避免在数学意义上考虑“积分”。在编译器术语中,它表示“整数类型”。