【问题标题】:Issue with "arithmetic operation resulted in overflow"“算术运算导致溢出”的问题
【发布时间】:2015-11-20 07:01:34
【问题描述】:

我有这个表情

 long balance = (long)answer.Find(DppGlobals.TAG_TI_BALANCE).Get_QWORD();

引发溢出的异常。右侧的值为无符号类型,值为:18446744073708240732。

如何避免这个异常,使用unchecked

PS 等效 C++ 实现返回余额 = -1310984,我这里也需要相同的值。

为什么会有这样的异常?


现在确实在 C# 端也使用 unchecked,我得到 -1310984。有人可以建议,我是否会以某种方式丢失数据?

【问题讨论】:

  • 那么堆栈跟踪是什么样的?确定在演员阵容中吗? Get_QWord() 的返回类型是什么? (顺便说一句,您是否有任何理由违反了正常的 .NET 命名约定和TAG_TI_BALANCE?)在不知道代码在做什么的情况下,很难给出好的建议。
  • @JonSkeet:是的,我检查过它肯定在演员阵容中。 QWORD 是 ulong。非常感谢您的建议

标签: c#


【解决方案1】:

使用uncheck 也会降低你的价值,但你不会有异常,你会得到错误号码。我想你会做一些改变你的代码的事情,而不是掩盖你的例外。

long balance = (unchecked))(long)answer.Find(DppGlobals.TAG_TI_BALANCE).Get_QWORD());

为什么会有这样的异常?

遇到错误是一件好事。因为如果您在一切都是数字的领域工作,您可能会出错并且不理解这一点。因此运行时会显示您的错误

【讨论】:

  • 是的,现在使用 unchecked 我在 C# 端也得到 -1310984。你确定它被裁剪是什么意思?
  • 如果它的范围不在 long 的范围内,它将裁剪您的数字。因此,如果您有(例如 int)一个大数字并且您尝试将其分配给 int 变量,它将裁剪适合 int 的数字。所以你会得到一个错误的数字
  • 我看到这个值最初被发送了很长时间。然后在我的问题中转换为 ulong 然后再次转换为 long 。为什么会溢出?
  • 因为ulong的范围比long大
  • @user200312:好吧,如果该值最初是 -1310984,那么您几乎肯定不应该将其转换为 ulong 开始......也许Get_QWORD() 应该返回一个long而是。
【解决方案2】:

鉴于 cmets,听起来您确实只需要使用未经检查的算术 - 但您应该关注 API 中 ulong 的使用。如果您的目标是仅传播 8 个字节的数据,并根据上下文将其解释为无符号整数或有符号整数,那么您很好 - 只要没有以“错误”形式对其执行算术运算。

理解为什么会发生这种情况很重要,而且用小数字更容易解释这一点。我将以bytesbyte 为例。 byte 的范围是 0 到 255(含)。 sbyte 的范围是 -128 到 127(含)。两者都可以存储 256 个不同的值。没问题。

现在,使用未经检查的转换,可以这么说:

byte a = GetByteFromSomewhere();
sbyte b = (sbyte) a;
StoreSByteSomewhere(b);
...
sbyte b = GetSByteFromStorage();
byte a = (byte) b;

如果这就是你正在做的全部,那很好。 byte 值为 -1 将变为 sbyte 值为 255,反之亦然 - 基本上它只是以不同方式解释相同的位模式。

但是,如果您在将值作为“错误”类型处理时对其执行其他操作,那么您可能会得到意想不到的答案。例如,考虑“除以 3”。如果你将 -9 除以 3,你会得到 -3,对吧?而如果你有:

byte original = -9;
sbyte converted = (sbyte) original;
sbyte divided = converted / 3;
byte result = (byte) divided;

...那么由于算法的工作方式,你最终得到的结果是 -2 而不是 -3。

现在这就是未选中转换的全部内容。当您进行 checked 转换时,它不仅会解释位 - 而是将值视为 数字。比如:

// In a checked context...
byte a = 128;
sbyte b = (sbyte) a; // Bang! Exception

这是因为 128(作为数字)超出了sbyte 的范围。这就是您的情况 - 数字 18446744073708240732 超出了long 的范围,因此您遇到了异常。经过检查的转换将其视为可以进行范围检查的数字,而不是未经检查的转换,只是将位重新解释为long(这会导致您想要的负数)。

【讨论】:

  • 亲爱的乔恩,我似乎很难完全理解你的答案,你能再细分一下吗?适合初学者风格?谢谢。
  • 还有,如果我直接有byte a = (byte) GetSByteFromStorage();?
  • @user200312:在不知道您被哪一点弄糊涂的情况下,“很难将其分解”。是的,转换方法调用的结果完全等同于将结果存储在局部变量中,然后再转换它。
  • @user200312:我刚刚意识到我没有包含任何关于异常的内容。现在会这样做。
  • 你确定这个byte result = (byte) original; 是正确的吗?最后一行。当它可能导致问题时我很困惑,我必须在哪里进行算术才能得到错误的结果?
猜你喜欢
  • 2011-05-15
  • 2011-05-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多