为什么以下c代码最终会进入无限循环?
for(unsigned char i = 0; i <= 0xff; i++){}
与以下结果相同:
for(unsigned char i = 0; i <= 0xff; ++i){}
我必须以哪种方式修改代码,以使其按预期工作(不使用int
或unsigned int
数据类型)?
答案 0 :(得分:17)
如果您确实需要使用unsigned char
,则可以使用
unsigned char i = 0;
do {
// ...
} while(++i);
当对unsigned
整数的算术运算突破其限制时,行为定义良好。因此,此解决方案将处理256个值(对于8位unsigned char
)。
答案 1 :(得分:8)
unsigned char
的范围是0到255(0xff)。添加1到0xff会产生0x100,当分配回unsigned char
时会回绕到0。
所以比较i <= 0xff
将永远为真。因此无限循环。
如果要在0xff之后停止循环,请使用int
作为数据类型。这个范围至少为-32767到32767,通常更多。
答案 2 :(得分:4)
典型的for
循环依赖于能够在循环的最后一次迭代之后检测终止条件。在您的情况下,正如其他答案所指出的那样,i <= 0xff
始终为真(假设i
属于unsigned char
类型而UCHAR_MAX==0xff
属于典型值。
您可以在任何整数类型的边界附近遇到同样的问题。例如,这个:
for (int i = INT_MAX - 9; i <= INT_MAX; i ++) {
/* ... */
}
(可能)也是一个无限循环(除了有符号整数类型的溢出具有未定义的行为,而不是无符号整数的明确定义的环绕语义,并且优化编译器可以利用它并且 - 但我离题)。不要那样做。
许多解决方案之一是在增量之前将测试移动到循环的底部:
for (unsigned char i = 0; ; i ++) {
printf("%d\n", i);
if (i == 0xff) break;
}
for
循环的第二个子句是终止条件,在每次迭代之前进行评估。如果你把它留空,它将被视为永远为真,给你一个无限循环(for (;;)
是一个简单的无限循环的常用习语)。我们测试循环底部的i
是否等于到0xff
。如果是,那么我们刚刚执行了最后一次迭代,我们就可以摆脱循环。
(有些人可能更喜欢在这里使用while
循环,但我喜欢for
因为它允许我们将循环控制变量的声明和单个构造中的增量结合起来。)
(严格来说,unsigned char
的最大值不一定是0xff
或255
,但它会出现在您可能遇到的任何系统上。对于某些DSP而言CHAR_BIT > 8
,因此UCHAR_MAX > 255
。)
答案 3 :(得分:2)
因为你是环绕的。无符号字符值的范围在0到255之间,并且因为无符号算术很好地定义,所以实际上将i
的值包装为0并且仍然满足条件并且无限期地继续迭代。
在有符号值的情况下,它是一个未定义的行为,并且存储在i中的值可能不是0.但它仍然会小于您可以存储在char中的最大值,并且仍然满足条件。