【问题标题】:Is C#/.NET signed integer overflow behavior defined?是否定义了 C#/.NET 有符号整数溢出行为?
【发布时间】:2014-10-06 21:25:52
【问题描述】:

在未经检查的上下文中,是否向具有值2147483647 的整数加一保证会导致-2147483648?

比如下面的代码

    const int first = int.MaxValue;
    int second = first;

    if ( second >= first )
    {
        Console.WriteLine( "First check" );
    }

    second++;

    if ( second >= first )
    {
        Console.WriteLine( "Second check" );
    }

在 C++ 中,打印“第一次检查”和“第二次检查”都是完全有效的,因为优化器可以将第一次检查的结果用于第二次检查。

C#也是这样吗?

【问题讨论】:

  • 您是否尝试过将数字加 1 并在调试器中检查它。它应该会产生 -2147483648
  • 说到.NET,编译器真的只有一个
  • @DJKRAZE:这并不意味着行为已定义(或未定义)。
  • @Steve 至少有三个编译器,所有这些都被使用。微软的原版、微软的 Roslyn 和 Mono 的。
  • @Cory:第一个隐含地回答了第二个。 C++ 优化器可以删除第二个分支的唯一原因是有符号整数溢出导致 UB。因此,优化器可以假设增量没有溢出。在 C# 中,行为已定义且有效,因此无法做出这样的假设。

标签: c# .net language-lawyer


【解决方案1】:

来自规范:

4.1.5 整数类型

已检查和未检查的运算符和语句用于控制整数类型算术运算和转换的溢出检查(第 7.6.12 节)。在检查的上下文中,溢出会产生编译时错误或引发 System.OverflowException。 在未经检查的上下文中,溢出将被忽略,任何不适合目标类型的高位都会被丢弃。

这是我能找到的对行为的唯一描述,但似乎已经足够了。所以是的,将 1 添加到 Int32.MaxValue 将导致值 Int32.MinValue 使用二进制补码表示。

【讨论】:

  • 规范是否还说必须使用二进制补码?我在 §4.1.5 中没有看到。
  • @svick C# 规范 (5.0) 说 int 是 System.Int32 的别名。 ECMA-335 (CLI) 规范(第 6 版)说 System.Int32 是等效于 CIL 程序集 int32 的类库类型,它被定义为“32 位二进制补码符号值”。所以,是的,假设一个兼容的 C# 编译器和 CIL 实现,C# ints 必须是二进制补码(int8、int16 和 int64 的情况类似)。
  • 请更正您的假设,将 Int32.MaxValue 加一将导致值为 -1。它实际上是 Int32.MinValue = -2147483648
  • 根据 this test,Int32.MaxValue+1 的结果是 -2147483648 而不是 -1。
【解决方案2】:

MSDN:

对于算术、强制转换或转换操作抛出一个 OverflowException,该操作必须发生在已检查的上下文中。经过 默认情况下,Visual Basic 中的算术运算和溢出是 检查;在 C# 中,它们不是。如果操作发生在未经检查的 在上下文中,通过丢弃任何高位位来截断结果 不适合目标类型。

【讨论】:

  • 如果你引用某个网页,你应该链接到它。
猜你喜欢
  • 2019-08-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-13
  • 1970-01-01
  • 1970-01-01
  • 2011-11-05
相关资源
最近更新 更多