1

我偶然发现了一个持续存在的问题,似乎没有合理的解释。问题似乎出在一个 for 循环中,该循环的for (i = size - 1; i >= 0; i--) {etc.}位置size是存储在内存缓冲区中的文件的大小,并且i是一个无符号整数。而不是停止 when i == 0,它环绕 - 从而导致i = 4294967295并导致分段错误。改变条件来i > 0解决问题。

不过,这样不是很奇葩吗?我一定错过了 for 循环如何在 C 中运行的一些关键部分。它不遵循这个方案:初始化、检查条件、递增/递减、检查条件等等?

任何帮助表示赞赏!

4

4 回答 4

8

无符号整数始终为>= 0

for (i = size - 1; i >= 0; i--) {etc.}

是一个无限循环如果i是一个unsigned int

于 2013-07-30T09:59:13.560 回答
2

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

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

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

于 2013-07-30T10:13:08.800 回答
1

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

因此,当您递减“0”时,它的完成方式2's complement1添加到0. 这是4294967295并且是最大值,它只是当所有 32 位都是 1 时。因此结果4294967295

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

一般来说,对于无符号类型,有一个环绕 from 0....MaxValue。当在上面递增时,MaxValue您从 重新输入00当低于你从重新输入递减MaxValue

于 2013-07-31T17:02:34.690 回答
1

根据C99标准:

6.2.5 类型

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

所以,这就是你的情况:

  • 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 */
}
于 2013-07-30T10:33:23.073 回答