考虑这个C代码:
#include "stdio.h"
int main(void) {
int count = 5;
unsigned int i;
for (i = count; i > -1; i--) {
printf("%d\n", i);
}
return 0;
}
我的观察/问题:循环永远不会被执行。但是,如果我将i的数据类型从unsigned int更改为int,则一切都按预期工作。
我一直在考虑将无符号整数作为当你试图从它们中减去时“环绕”的值。因此,当i为零并且我减去1时,它将回绕到UINT_MAX。而且由于它的价值永远不会消极,这实际上是一个无限循环。 (当我将比较从i> -1更改为i> = 0时,就会发生这种情况。)
我的逻辑中存在某个错误,因为如果我是无符号的,那么循环永远不会被执行,我将它与-1进行比较。要么编译器以某种方式对其进行优化,要么运行时值的行为与我期望的不同。
为什么循环不能运行?
答案 0 :(得分:18)
在i > -1
中,-1转换为unsigned int
,结果为UINT_MAX
。 i
永远不会大于该值,因此循环体永远不会执行。
您可能会发现可以说服编译器警告您:在条件上下文中使用always-true或always-false表达式。但如果你写了i > -2
,那对你仍然无济于事,所以你也可能会发现你可以为所有混合符号比较启用警告。
请注意,在C中,算术始终使用相同类型的操作数执行。这包括比较,但IIRC不是班次运营商。如果操作数是不同类型的,如在这种情况下,则转换它们中的至少一个以使它们成为相同的类型。计算目的地类型的规则见6.3.1.1/2和6.3.1.8/1。
答案 1 :(得分:3)
当您在“类型对称”二进制操作中混合相同宽度的有符号和无符号操作数时(例如,在您的示例中为+
,*
或>
),无符号类型“wins”并在无符号域中评估操作。即签名操作数转换为无符号类型。
在您的示例中,整数常量的类型为signed int
,而i
的类型为unsigned int
。操作数具有相同的宽度,因此在您的示例i > -1
中,i > (unsigned) -1
被解释为i > UINT_MAX
,相当于{{1}}。这就是你的循环永远不会被执行的原因。
答案 2 :(得分:0)
-1变为UINT_MAX
。由于没有数字大于该数,因此循环条件永远不会为真,并且永远不会输入循环。
如果你把它改成实际上你可能不应该在这种情况下使用无符号: - )i >= 0
,那应该按预期工作。
答案 3 :(得分:0)
无论您是处理无符号数字还是有符号数字,-1都将始终编译为0xffffffff。处理器具有有符号和无符号比较标志。将该数字与5进行比较时,签名标志会将其视为-1,并将其视为较小,但无符号标志会将其视为一个较大的数字,并说它更大。由于该数字也与UINT_MAX相同,因此对于所有无符号数字,您的比较将为false。