int16溢出导致死循环

int16 overflow leading to infinite loop

正如我们所知,int16_t 的最大值为 32767,因此下面的代码将只是循环:

for (int16_t i = 0; i < 65535; i++) {
  // infinite loop
}

当我更改代码时,它也会循环:

const int32_t t = 65535;
for (int16_t i = 0; i < t; i++) {
  // infinite loop
}

但是当我把它变成 uint32_t 而不是 int32_t 时,它实际上退出了:

const uint32_t t = 65535;
for (int16_t i = 0; i < t; i++) {
  // actually exits
}

这是因为它为我做了一些编译器把戏吗?我假设在进行比较时:

i < t

对于最后一个版本,它会为我自动转换吗?但是我不明白为什么它在上一个版本中仍然存在...

当您比较有符号类型和无符号类型时,有符号类型会在执行比较之前提升为无符号类型。因此,最后一段代码有效。


看看下面的程序

#include <iostream>
#include <cstdint>

int main()
{
   const uint32_t t = 65535;
   int16_t i = 32765;
   for (; i < t; i++)
   {
      std::cout << i << ", " << static_cast<uint32_t>(i) << std::endl;
   }
   std::cout << i << ", " << static_cast<uint32_t>(i) << std::endl;
}

及其使用 g++ 6.4.0 的输出

32765, 32765
32766, 32766
32767, 32767
-32768, 4294934528

在整数溢出点,i的值从最大值翻转到最小值。更重要的是,当这个数字提升到 uint32_t 时,它似乎是一个很大的值。

4294934528uint32_t中的二进制表示为:

11111111 11111111 10000000 00000000

-32768int16_t中的二进制表示为:

                  10000000 00000000

虽然我不完全理解将有符号类型提升为无符号类型的规则是什么来解释相关性,但似乎存在相关性。