【问题标题】:Integer overflow in operations运算中的整数溢出
【发布时间】:2013-04-03 23:06:00
【问题描述】:

以下代码:

UINT32 dword = 4294967295;

if(dword + 1 != 0) // condition

在此类操作中,是否始终使用最大(整个)寄存器(可用于架构)?以上条件在 64 位模式下始终为真,而在 32 位模式下为假?

【问题讨论】:

  • 我相信标准规定了整数溢出会发生什么,尽管我不记得具体细节了。当然,UINT32 在 32 位和 64 位架构上的大小相同,因此您希望它的行为相同。
  • @MarkRansom:无符号溢出包装。有符号溢出具有未定义的行为。

标签: c++ x86 x86-64 integer-overflow


【解决方案1】:

这取决于UINT32 的真正类型。

如果它是无符号类型(如您所料),则保证结果会以可表示的最大值 + 1 为模减少,因此代码如下:

if (std::numeric_limits<T>::is_unsigned)
    assert(std::numeric_limits<T>::max()+1==0);

...应该会成功。 OTOH,根据名称,我们通常希望它是 32 位类型,而不管实现、寄存器大小等如何,因此我们希望得到相同的结果。

编辑:[对不起,不得不停下来喂宝宝几分钟]我应该补充更多细节。尽管我们当然希望在实践中不太可能,但可以想象UINT32 可能真的是(比如说)一个 16 位的unsigned short。为了便于讨论,我们假设int 是32 位。

在这种情况下,dword+1 将涉及 unsigned shortint1 的隐式类型)之间的数学运算。在这种情况下,dword 实际上将被初始化为 65535。然后,当您进行添加时,65535 将被提升为 32 位 int,而 1 将被添加为 int,所以结果将是 65536。

至少在理论上,如果 UINT32 是无符号 32 位类型(如我们所料)但 int 是 64 位类型,则可能会发生相同的基本情况。同样,dword 在进行数学运算之前将被提升为 int,因此数学运算将在 64 位而不是 32 位上完成,因此(再次)结果不会回绕为 0。

【讨论】:

  • 使用std::numeric_limits&lt;T&gt;::is_unisgned 让我的代码闻起来是紫色的:P
  • "取模后可以表示的最大值"加一
  • 对于语言律师的观点:如果 UINT32 是 32 位 unsigned short,并且 int 是 33 位签名的,则代码具有未定义的行为。哇!
  • @NikBougalis:谢谢——终于明白了。
  • @JerryCoffin 嘿,天色已晚……必须用点幽默来继续前进。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-12
  • 1970-01-01
  • 1970-01-01
  • 2021-07-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多