在 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# 编译器选项定义了如何处理 checked
和 unchecked
之外的表达式:/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# 中处理整数溢出的最佳方法?的主要内容,如果未能解决你的问题,请参考以下文章
RandomizedSearchCV 溢出错误:无法将“int”放入索引大小的整数中