C++ 中 unsigned char 的溢出

Overflow of an unsigned char in C++

我在此处 https://www.toptal.com/c-plus-plus/interview-questions 找到了以下代码片段,问题是:此循环将执行多少次?解释你的答案

unsigned char half_limit = 150;

for (unsigned char i = 0; i < 2 * half_limit; ++i)
{
    // do something;
}

答案是无限的。

The expression 2 * half_limit will get promoted to an int (based on C++ conversion rules) and will have a value of 300. However, since i is an unsigned char, it is rerepsented by an 8-bit value which, after reaching 255, will overflow (so it will go back to 0) and the loop will therefore go on forever.

我猜了45次(300-255),因为我记得如果你递增一个无符号整数计数器,计数器溢出时会再次从0开始。好的,所以它从整数转换为无符号字符,那为什么不是 255?

谢谢

小于 int 的类型的算术首先将它们提升为 int。因此 2 * half_limit300。假设unsigned char能表示的最大值是255,那么所有的值i都可能满足i < 2 * half_limit,这样就死循环了。

2 * half_limit

等同于:

int(2) * int(half_limit)

half_limit 被提升为整数进行乘法运算,表达式的结果为 300。因此,

i < 2 * half_limit

变成

i < int(300)

其中 i 被提升为 int 以进行实际比较,但由于 i 是一个无符号字符,它永远不能大于 255(假设我们的无符号字符为 8 位),因此比较有效:

int(smaller than 256) < int(300)

当然,这总是正确的。

why its not 255 then?

因为255小于300。下一次迭代,i为0,也小于300。8位整数表示的数都不能达到300。


从技术上讲,正确答案是迭代次数取决于 unsigned char 的大小。在使用 16 位字节的系统上,不会有问题。

答案的另一个问题是 "infinite" 循环在语言中是不允许的,除非在循环中执行某些操作——例如生成一些输出。所以实际上,示例程序具有未定义的行为(假设 8 位字节)。引用自 标准:

[intro.progress]

The implementation may assume that any thread will eventually do one of the following:

  • terminate,
  • make a call to a library I/O function,
  • perform an access through a volatile glvalue, or
  • perform a synchronization operation or an atomic operation.

[ Note: This is intended to allow compiler transformations such as removal of empty loops, even when termination cannot be proven. — end note ]

#include <iostream>

int main(int argc,char* argv[]){

    unsigned char half_limit = 150;

    for (unsigned char i = 0; i < 2 * half_limit; ++i)
    {
        printf("%.2X\n", i);
    }
}

使用 mingw g++ 编译了这段代码。给了我一个无限循环,打印十六进制 i 的值表明它每次溢出时都会重置。也许当它溢出时它会设置一个标志.. 如果我错了请纠正我