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_limit
是 300
。假设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 的值表明它每次溢出时都会重置。也许当它溢出时它会设置一个标志..
如果我错了请纠正我
我在此处 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_limit
是 300
。假设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 的值表明它每次溢出时都会重置。也许当它溢出时它会设置一个标志.. 如果我错了请纠正我