我知道较低的数据类型会转换为较高的数据类型(例如 int -> unsigned int -> float -> 等),但我不确定以下内容:
int var = 5u - 10; // var = -5
auto var = 5u - 10; // var = 4294967291
5u 是无符号的,但在第一种情况下,为什么 -10 (有符号整数)不转换为无符号值,而在第二种情况下呢?在第一种情况下,有符号值不会转换为无符号值,这对我来说很奇怪
没有“有符号整数文字”:5u - 10
实际上是从 5u 中减去 10。
(减法)的结果是无符号的,并且会溢出,结果是“比溢出的 0 少 5 个数字”(4294967291 = 2 32 -5)
第一条语句初始化 a int
,因此无符号编译时间常数被重新解释为 int。结果是正确的 (-5),因为您的硬件使用 2s 补码算法。(-5 和 4294967291 是相同的 32 位模式)
第二条语句初始化一个变量,其类型由文字推断。它是unsigned
。
您的两个示例的右侧都完全在无符号类型的域中工作。即您的两个表达式的5u - 10
行为相同,这并不奇怪,因为它们是相同的。在任何一种情况下,表达式中都没有转换为int
(您似乎错误地假设) 。5u - 10
表达式5u - 10
总是在无符号类型的域中计算并产生等于的无符号结果UINT_MAX + 1 - 5
。在第一次初始化中,您尝试将该值强制转换为 type 的变量int
,这会导致实现定义的行为溢出。在您的情况下,您的实现表现得如此var
获得了 value -5
。换句话说,您最终得到的事实-5
在var
抽象 C++ 语言领域没有明确的解释。您观察到的结果只是编译器的一个怪癖。在其他一些编译器中,第一次初始化可能会在var
.
在第二种情况下,表达式的类型(也就是unsigned
)变成了变量的类型,变量用无符号值初始化,没有任何溢出。
首先,因为您使用auto
,编译器将unsigned
在您的第二个示例中选择。
有符号和无符号数字在内部以相同的方式存储。这只是数字在打印时的解释方式会有所不同[在比较中,因为“负”有符号数字低于 0,其中无符号数字不能小于零] - 检查有符号数字如果它们是“负数”,则打印为减号和否定的原始数字。无符号数字仅被视为打印时内部表示的任何内容。
因此,您看到的值只是同一数字的两种不同表示形式——分别是有符号和无符号。
在 C 和 C++ 中,在绝大多数情况下,表达式的类型由表达式本身决定,而不考虑它出现的上下文。
int var = 5u - 10;
5u
是类型unsigned int
;10
是类型int
。-
运算符的规则使int
参数转换为unsigned int
,使表达式等效于5u - 10u
。结果是UINT_MAX + 1 - 10
,一个非常大的数字。初始化隐式地将 this 从 转换unsigned int
为signed int
。由于该值(几乎可以肯定)不能表示为int
,因此转换的结果是实现定义的。在几乎所有现有实现中,转换只是将无符号表示重新解释为有符号值,从而导致-5
. (这适用于使用二进制补码表示负值的系统;有符号/无符号转换的简单性是二进制补码如此广泛使用的原因之一。)
请注意,不可能var
拥有 value 4294967291
; an 可以在您的系统上保存的最大值int
是(可能)2147483647
。
auto var = 5u - 10;
5u - 10
以与以前相同的方式进行评估,导致, 或在您的系统上的unsigned int
结果。采用表达式类型的均值,因此不执行转换。(在具有 16 位 的系统上,结果将是。)UINT_MAX + 1 - 5
4294967291
auto
var
unsigned int
int
65531
在回答您的问题时,在这两种情况下,常量10
都会从转换int
为unsigned int
。