标准的相关引用:
5 表达式 [expr]
10 许多期望算术或枚举类型的操作数的二元运算符会导致转换并以类似的方式产生结果类型。目的是产生一个通用类型,这也是结果的类型。这种模式称为通常的算术转换,定义如下:
[省略等号类型或等号类型的 2 条子句]
— 否则,如果无符号整数类型的操作数的秩大于或等于另一个操作数类型的秩,则将有符号整数类型的操作数转换为无符号整数类型的操作数的类型。
— 否则,如果带符号整数类型的操作数的类型可以表示无符号整数类型的操作数类型的所有值,则将无符号整数类型的操作数转换为有符号整数类型的操作数的类型。
— 否则,两个操作数都应转换为与带符号整数类型的操作数类型对应的无符号整数类型。
让我们考虑以下 3 个示例案例,用于系统上的上述 3 个子句中的每个子句,其中sizeof(int) < sizeof(long) == sizeof(long long)
(很容易适应其他情况)
#include <iostream>
signed int s1 = -4;
unsigned int u1 = 2;
signed long int s2 = -4;
unsigned int u2 = 2;
signed long long int s3 = -4;
unsigned long int u3 = 2;
int main()
{
std::cout << (s1 + u1) << "\n"; // 4294967294
std::cout << (s2 + u2) << "\n"; // -2
std::cout << (s3 + u3) << "\n"; // 18446744073709551614
}
带输出的实时示例。
第一个子句:相等等级的类型,因此signed int
操作数转换为unsigned int
. 这需要一个值转换,它(使用二进制补码)给出打印值。
第二条:有符号类型有更高的等级,并且(在这个平台上!)可以表示无符号类型的所有值,所以无符号操作数被转换为有符号类型,你得到-2
第三个子句:有符号类型再次具有更高的等级,但是(在这个平台上!)不能表示无符号类型的所有值,因此两个操作数都转换为unsigned long long
,并且在对有符号操作数进行值转换后,您会得到打印的值。
请注意,当无符号操作数足够大(例如,这些示例中为 6)时,由于无符号整数溢出,最终结果将为所有 3 个示例给出 2。
(已添加)请注意,当您对这些类型进行比较时,您会得到更多意想不到的结果。让我们考虑上面的示例 1 <
:
#include <iostream>
signed int s1 = -4;
unsigned int u1 = 2;
int main()
{
std::cout << (s1 < u1 ? "s1 < u1" : "s1 !< u1") << "\n"; // "s1 !< u1"
std::cout << (-4 < 2u ? "-4 < 2u" : "-4 !< 2u") << "\n"; // "-4 !< 2u"
}
由于2u
是由后缀unsigned
明确提出的,因此u
适用相同的规则。在用 C++ 编写时比较-4 < 2时,结果可能不是您所期望的-4 < 2u
......