C for循环表现奇怪

时间:2013-07-30 09:57:23

标签: c for-loop

我偶然发现了一个持久的问题,似乎没有一个合理的解释。问题似乎在于for (i = size - 1; i >= 0; i--) {etc.}的for循环中,其中size是存储在内存缓冲区中的文件的大小,i是无符号整数。而不是在i == 0时停止,它会缠绕 - 从而导致i = 4294967295并导致分段错误。将条件更改为i > 0可以解决问题。

然而,这不是特别的吗?我必须忽略for循环如何在C中运行的一些关键部分。它不遵循这个方案:初始化,检查条件,递增/递减,检查条件等等吗?

感谢任何帮助!

4 个答案:

答案 0 :(得分:8)

无符号整数始终为>= 0

for (i = size - 1; i >= 0; i--) {etc.}
如果iunsigned int

是无限循环。

答案 1 :(得分:2)

让我们看看当i接近0时会发生什么。

  • i == 1:循环从i >= 0开始正常执行。从i减去1。现在i包含0。
  • i == 0:循环从i >= 0开始正常执行。从i减去1。因为i是无符号的,所以它会环绕。因此,i现在包含4294967295。
  • i == 4294967295:循环从i >= 0
  • 开始正常执行
  • 等......

解决方案是测试其他内容(例如i > 0,就像您的示例一样),或者在每次迭代和循环时增加i,同时小于文件的大小。< / p>

答案 2 :(得分:1)

根据C99标准:

  

6.2.5类型

     

9)[...]涉及无符号操作数的计算永远不会溢出,因为   结果无法由结果无符号整数表示   type是以大于最大值的数量减少的模数   可以由结果类型表示的值。

所以,这就是你的情况:

  • i == 1,因此i--会产生i == 0
  • i == 0,因此i--会导致环绕并i == UINT_MAX
  • i == UINT_MAX,因此i--会产生i == UINT_MAX - 1,依此类推。

修复循环的一种方法是使用以下(https://stackoverflow.com/a/665773/676939):

for (i = size; i-- > 0;){
    /* yada yada yada */
}

另外一种做法是:(https://stackoverflow.com/a/665758/676939):

unsigned fake_i;
for (fake_i = size; fake_i > 0; i--){
    unsigned i = fake_i - 1;
    /* Do something with i */
}

答案 3 :(得分:1)

在无符号类型中,最高有效位不被视为符号位。 在你的情况下,unsigned int有4bytes(32 bits)

因此,当您递减'0'时,2's complement的{​​{1}}被添加到1。 这是0并且是最大值,但是当所有32位都是1时,它都是最大值。 因此结果为4294967295

从最大值4294967295递增时(即当所有32位为1时) 递增这会使所有低32位为0,而4294967295位为1。因此,对于unsigned int,32nd位溢出超出4字节的范围。 因此,该值变为0。

一般来说,对于无符号类型,有32nd的回绕。 递增高于0....MaxValue时,您会从MaxValue重新输入。 递减到0以下时,您会从0重新输入。