为什么C不运行unsigned int与负值的比较?

时间:2011-06-02 17:14:28

标签: c optimization unsigned-integer

考虑这个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进行比较。要么编译器以某种方式对其进行优化,要么运行时值的行为与我期望的不同。

为什么循环不能运行?

4 个答案:

答案 0 :(得分:18)

i > -1中,-1转换为unsigned int,结果为UINT_MAXi永远不会大于该值,因此循环体永远不会执行。

您可能会发现可以说服编译器警告您:在条件上下文中使用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。