理解有符号比较和无符号比较

6

有人能告诉我为什么if条件是假的吗?

#include <iostream>
using namespace std;

int main(int argc, char *argv[])
{
    int a;
    unsigned int ua;

    a = -1;
    ua = a;

    cout << "ua: " << ua << endl;
    if (ua != -1)
        cout << "Is unsigned" << endl;
    else
        cout << "Is signed" << endl;

    return 0;
}

我的意思是,这里ua == int_max_value,不是-1,但当我运行它时,输出结果是“有符号的”。

2
“-1” 被转换为无符号整数以进行比较。 - T.C.
如果将-1转换为无符号整数,它怎么能表示-1呢?我的意思是,-1是有符号的 :S - harryPoker
2
“-1”使用二进制补码算法转换后,结果为“UINT_MAX”。这只是因为C++有一个非常强的“倾向”,将所有东西都转换为无符号整数(关于何时发生这种情况的确切规则相当复杂,请参阅C++标准以获取详细信息)。 - Rufflewind
@harryPoker:它本身不是有符号的,但在转换时会重新变为有符号的! - Lightness Races in Orbit
2个回答

4
在算术类型上执行的!===运算符会对其操作数执行称为“通常算术转换”的操作。在这里相关的情况下,给定一个类型为unsigned X和一个类型为signed X的操作数,其中Xintlonglong long中的一种,通常的算术转换将有符号操作数转换为无符号类型,然后再进行比较。
因此,当您比较ua(类型为unsigned int)和-1(类型为signed int)时,-1被转换为unsigned int类型(概念上通过添加2的32次方以假设32位int),然后结果与ua的值相等。

太好了!现在我的心可以安心了 :) - harryPoker

1
这是期望的行为,如果操作数属于算术类型,则"!="运算符将对其进行常规算术转换。这在C++标准草案第5.10节“相等运算符”中有所涵盖,其中说到:

如果两个操作数都是算术或枚举类型,则对两个操作数执行通常的算术转换;如果指定的关系为真,则每个操作符应返回true,否则返回false。

在这种情况下,这将导致整数提升,从而将"-1"转换为无符号整型。这在第5段第10节结束时有所涵盖,该段落写道:

否则,如果具有无符号整数类型的操作数的秩大于或等于另一个操作数的类型的秩,则应将具有有符号整数类型的操作数转换为具有无符号整数类型的操作数的类型。


谢谢!现在我完全理解了 :) - harryPoker
请注意,引用的特定段落在C++14中发生了变化,但行为仍然相同。相关论文为N3624 - T.C.
此外,将“-1”转换为无符号数并不属于整型提升。 - T.C.
@T.C. C++14相对于整数提升部分更简单。在“5 p 10”中,它说:“否则,应对两个操作数执行整数提升(4.5)。” - Shafik Yaghmour
@ShafikYaghmour 如果你看一下引用的那一部分,对于已经是int类型的操作数,积分提升并不适用。在应用任何积分提升(如果有)后,才会进行到unsigned的转换。 - T.C.
在C99和C11中,它实际上是这样说的:'所有其他类型都不会因为整数提升而发生改变。' 因此,尽管不需要进行任何更改,但我始终将其视为一种提升,但也许我的解释是错误的。 - Shafik Yaghmour

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接