标准中相关引用:
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";
std::cout << (s2 + u2) << "\n";
std::cout << (s3 + u3) << "\n";
}
现场示例,包含输出。
第一条子句:类型等级相同,因此将 signed int
操作数转换为 unsigned int
。这涉及到一个值变换,(使用二进制补码)得出打印的值。
第二个子句:有符号类型具有更高的等级,并且(在该平台上!)可以表示无符号类型的所有值,因此将无符号操作数转换为有符号类型,您会得到 -2。
第三个子句:有符号类型再次具有更高的等级,但是(在该平台上!)不能表示无符号类型的所有值,因此两个操作数都将转换为 unsigned long long
,并在对有符号操作数进行值变换后,您会得到打印的值。
请注意,当无符号操作数足够大(例如,在这些示例中为 6)时,由于无符号整数溢出,最终结果将给出所有 3 个示例的值为 2。
(添加)请注意,当您对这些类型进行比较时,会得到更多意想不到的结果。让我们考虑上面的第一个示例,使用<
:
#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"
}
由于u
后缀将2u
明确地定义为无符号类型,因此相同的规则适用。当在C++中写 -4 < 2u
进行比较时,结果可能与您期望的不同...