我偶然发现了一个持久的问题,似乎没有一个合理的解释。问题似乎在于for (i = size - 1; i >= 0; i--) {etc.}
的for循环中,其中size
是存储在内存缓冲区中的文件的大小,i
是无符号整数。而不是在i == 0
时停止,它会缠绕 - 从而导致i = 4294967295
并导致分段错误。将条件更改为i > 0
可以解决问题。
然而,这不是特别的吗?我必须忽略for循环如何在C中运行的一些关键部分。它不遵循这个方案:初始化,检查条件,递增/递减,检查条件等等吗?
感谢任何帮助!
答案 0 :(得分:8)
无符号整数始终为>= 0
。
for (i = size - 1; i >= 0; i--) {etc.}
如果i
是unsigned 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
重新输入。