for (unsigned char i = 0; i<=0xff; i++) 产生无限循环
for (unsigned char i = 0; i<=0xff; i++) produces infinite loop
为什么下面的 c 代码会陷入死循环?
for(unsigned char i = 0; i <= 0xff; i++){}
结果相同:
for(unsigned char i = 0; i <= 0xff; ++i){}
我必须以何种方式修改代码,使其按预期工作(不使用 int
或 unsigned int
数据类型)?
因为你环绕。一个 unsigned char 值的范围在 0-255 之间,并且因为 unsigned 算术是很好定义的,你实际上将 i
的值包装到 0 并且条件仍然满足并且迭代继续无限。
在有符号值的情况下,它是未定义的行为,存储在 i 中的值可能不是 0。但它仍然会小于您可以存储在 char 中的最大值并且仍然满足条件。
unsigned char
的范围是 0 到 255 (0xff)。将 1 加到 0xff 得到 0x100,当它被分配回一个 unsigned char
时又回到 0.
因此比较 i <= 0xff
将始终为真。因此无限循环。
如果希望循环在 0xff 之后停止,请使用 int
作为数据类型。这个范围至少是 -32767 到 32767,通常更多。
如果你真的需要使用unsigned char
那么你可以使用
unsigned char i = 0;
do {
// ...
} while(++i);
当对 unsigned
整数的算术运算超出其限制时,行为已明确定义。所以这个解决方案将处理 256 个值(对于 8 位 unsigned char
)。
典型的 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
。)
为什么下面的 c 代码会陷入死循环?
for(unsigned char i = 0; i <= 0xff; i++){}
结果相同:
for(unsigned char i = 0; i <= 0xff; ++i){}
我必须以何种方式修改代码,使其按预期工作(不使用 int
或 unsigned int
数据类型)?
因为你环绕。一个 unsigned char 值的范围在 0-255 之间,并且因为 unsigned 算术是很好定义的,你实际上将 i
的值包装到 0 并且条件仍然满足并且迭代继续无限。
在有符号值的情况下,它是未定义的行为,存储在 i 中的值可能不是 0。但它仍然会小于您可以存储在 char 中的最大值并且仍然满足条件。
unsigned char
的范围是 0 到 255 (0xff)。将 1 加到 0xff 得到 0x100,当它被分配回一个 unsigned char
时又回到 0.
因此比较 i <= 0xff
将始终为真。因此无限循环。
如果希望循环在 0xff 之后停止,请使用 int
作为数据类型。这个范围至少是 -32767 到 32767,通常更多。
如果你真的需要使用unsigned char
那么你可以使用
unsigned char i = 0;
do {
// ...
} while(++i);
当对 unsigned
整数的算术运算超出其限制时,行为已明确定义。所以这个解决方案将处理 256 个值(对于 8 位 unsigned char
)。
典型的 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
。)