【问题标题】:Best way to handle Integer overflow in C#?在 C# 中处理整数溢出的最佳方法?
【发布时间】:2011-02-26 15:39:15
【问题描述】:

处理整数溢出是一项常见任务,但在 C# 中处理它的最佳方法是什么?是否有一些语法糖使它比其他语言更简单?或者这真的是最好的方法吗?

int x = foo();
int test = x * common;
if(test / common != x)
    Console.WriteLine("oh noes!");
else
    Console.WriteLine("safe!");

【问题讨论】:

  • 最好的方法是首先预防
  • 当然,但这与这里提出的问题不同。处理它和防止它是单独的(当然是相关的)讨论。

标签: c# .net integer overflow


【解决方案1】:

我不需要经常使用这个,但是你可以使用checked关键字:

int x = foo();
int test = checked(x * common);

如果溢出将导致运行时异常。来自 MSDN:

在检查的上下文中,如果表达式产生的值是 在目标类型范围之外,结果取决于 表达式是常量还是非常量。持续的 表达式导致编译时错误,而非常量表达式 在运行时进行评估并引发异常。

我还应该指出,还有另一个 C# 关键字 unchecked,它当然与 checked 相反并且忽略溢出。您可能想知道您何时使用过unchecked,因为它似乎是默认行为。好吧,有一个 C# 编译器选项定义了如何处理 checkedunchecked 之外的表达式:/checked。您可以在项目的高级构建设置下进行设置。

如果您有很多表达式需要检查,最简单的做法实际上是设置/checked 构建选项。那么任何溢出的表达式,除非包裹在 unchecked 中,都会导致运行时异常。

【讨论】:

  • 为什么不勾选默认行为?使用checked有性能问题吗?
  • @KFL "因为检查溢出需要时间,所以在没有溢出危险的情况下使用未经检查的代码可能会提高性能。但是,如果可能发生溢出,则应使用检查环境。”见msdn.microsoft.com/en-us/library/a569z7k8.aspx。我也相信默认是未选中的,因为它与 C/C++ 行为相似。
  • 在某些情况下溢出很有用,例如 TCP 序列号。一个无符号的 int 只是环绕为零,所以只需要增量运算符。
  • 如果所有机器上溢出,未选中是否会产生相同的结果??
  • 更新了 'checked' 的 url 参考 - msdn.microsoft.com/en-us/library/74b4xzyw(v=vs.140).aspx
【解决方案2】:

试试下面的

int x = foo();
try {
  int test = checked (x * common);
  Console.WriteLine("safe!");
} catch (OverflowException) {
  Console.WriteLine("oh noes!");
}

【讨论】:

    【解决方案3】:

    最好的方法是如 Micheal 所说 - 使用 Checked 关键字。 这可以这样做:

    int x = int.MaxValue;
    try   
    {
        checked
        {
            int test = x * 2;
            Console.WriteLine("No Overflow!");
        }
    }
    catch (OverflowException ex)
    {
       Console.WriteLine("Overflow Exception caught as: " + ex.ToString());
    }
    

    【讨论】:

    • 你需要格式化你的代码(在它前面插入4个空格,网站会自动选择格式化和语法高亮。
    【解决方案4】:

    旧线程,但我刚刚遇到了这个。我不想使用异常。我最终得到的是:

    long a = (long)b * (long)c;
    if(a>int.MaxValue || a<int.MinValue)
        do whatever you want with the overflow
    return((int)a);
    

    【讨论】:

    • 这行不通。 int.MaxValue + 1 给你 -2147483648 或 int.MinValue。所以a 永远不能大于 MaxValue 或小于 MinValue。将数字想象成这样的一条线:-2147483648, -2147483647, ... 0 ... 2147483646, 2147483647 当您超过最大值时,它会流回最小值。
    • 您错过了他/她在检查 int 边界之前转换为 long 的事实。所以只要它不溢出 long 就可以工作。
    【解决方案5】:

    有时,最简单的方法是最好的方法。我想不出更好的方式来写你写的东西,但你可以把它写成:

    int x = foo();
    
    if ((x * common) / common != x)
        Console.WriteLine("oh noes!");
    else
        Console.WriteLine("safe!");
    

    请注意,我没有删除 x 变量,因为调用 foo() 三次会很愚蠢。

    【讨论】:

    • 现在我想知道编译器是否会完全优化该表达式?
    • USefull,除非您当然打算使用结果 (x*common),在这种情况下,您的缩短将需要计算两次...
    【解决方案6】:

    所以,我在事后遇到了这个问题,它主要回答了我的问题,但对于我的特殊情况(如果其他人有相同的要求),我想要任何会溢出签名的正值的东西int 只是解决int.MaxValue:

    int x = int.MaxValue - 3;
    int someval = foo();
    
    try
    {
       x += someval;
    }
    
    catch (OverflowException)
    {
       x = int.MaxValue;
    }
    

    【讨论】:

    • 除非您使用/checked 编译或使用checked 关键字,否则不会抛出异常,对吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-05-16
    • 2013-04-17
    • 1970-01-01
    • 2011-01-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多