在 C# 中处理整数溢出的最佳方法?

Posted

技术标签:

【中文标题】在 C# 中处理整数溢出的最佳方法?【英文标题】:Best way to handle Integer overflow in 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!");

【问题讨论】:

最好的方法是首先预防 当然,但这与这里提出的问题不同。处理它和防止它是单独的(当然是相关的)讨论。 【参考方案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 关键字,否则不会抛出异常,对吗?

以上是关于在 C# 中处理整数溢出的最佳方法?的主要内容,如果未能解决你的问题,请参考以下文章

C# 捕获堆栈溢出异常

RandomizedSearchCV 溢出错误:无法将“int”放入索引大小的整数中

python不是用来处理整数溢出的吗?

确定整数溢出是不是超过或低于界限

C# Dictionary源码剖析---哈希处理冲突的方法有:开放定址法再哈希法链地址法建立一个公共溢出区等

两种解释整数溢出的方法