3

我知道较低的数据类型会转换为较高的数据类型(例如 int -> unsigned int -> float -> 等),但我不确定以下内容:

int var = 5u - 10; // var = -5
auto var = 5u - 10; // var = 4294967291

5u 是无符号的,但在第一种情况下,为什么 -10 (有符号整数)不转换为无符号值,而在第二种情况下呢?在第一种情况下,有符号值不会转换为无符号值,这对我来说很奇怪

4

4 回答 4

4

没有“有符号整数文字”:5u - 10实际上是从 5u 中减去 10。

(减法)的结果是无符号的,并且会溢出,结果是“比溢出的 0 少 5 个数字”(4294967291 = 2 32 -5)

第一条语句初始化 a int,因此无符号编译时间常数被重新解释为 int。结果是正确的 (-5),因为您的硬件使用 2s 补码算法。(-5 和 4294967291 是相同的 32 位模式)

第二条语句初始化一个变量,其类型由文字推断。它是unsigned

于 2013-02-11T18:24:25.577 回答
3

您的两个示例的右侧都完全在无符号类型的域中工作。即您的两个表达式的5u - 10行为相同,这并不奇怪,因为它们是相同的。在任何一种情况下,表达式中都没有转换为int(您似乎错误地假设) 。5u - 10

表达式5u - 10总是在无符号类型的域中计算并产生等于的无符号结果UINT_MAX + 1 - 5。在第一次初始化中,您尝试将该值强制转换为 type 的变量int,这会导致实现定义的行为溢出。在您的情况下,您的实现表现得如此var获得了 value -5。换句话说,您最终得到的事实-5var抽象 C++ 语言领域没有明确的解释。您观察到的结果只是编译器的一个怪癖。在其他一些编译器中,第一次初始化可能会在var.

在第二种情况下,表达式的类型(也就是unsigned)变成了变量的类型,变量用无符号值初始化,没有任何溢出。

于 2013-02-11T18:30:21.067 回答
2

首先,因为您使用auto,编译器将unsigned在您的第二个示例中选择。

有符号和无符号数字在内部以相同的方式存储。这只是数字在打印时的解释方式会有所不同[在比较中,因为“负”有符号数字低于 0,其中无符号数字不能小于零] - 检查有符号数字如果它们是“负数”,则打印为减号和否定的原始数字。无符号数字仅被视为打印时内部表示的任何内容。

因此,您看到的值只是同一数字的两种不同表示形式——分别是有符号和无符号。

于 2013-02-11T18:22:37.327 回答
1

在 C 和 C++ 中,在绝大多数情况下,表达式的类型由表达式本身决定,而不考虑它出现的上下文。

int var = 5u - 10;

5u是类型unsigned int10是类型int-运算符的规则使int参数转换为unsigned int,使表达式等效于5u - 10u。结果是UINT_MAX + 1 - 10,一个非常大的数字。初始化隐式地将 this 从 转换unsigned intsigned int。由于该值(几乎可以肯定)不能表示为int,因此转换的结果是实现定义的。在几乎所有现有实现中,转换只是将无符号表示重新解释为有符号值,从而导致-5. (这适用于使用二进制补码表示负值的系统;有符号/无符号转换的简单性是二进制补码如此广泛使用的原因之一。)

请注意,不可能var拥有 value 4294967291; an 可以在您的系统上保存的最大值int是(可能)2147483647

auto var = 5u - 10;

5u - 10以与以前相同的方式进行评估,导致, 或在您的系统上的unsigned int结果。采用表达式类型的均值,因此不执行转换。(在具有 16 位 的系统上,结果将是。)UINT_MAX + 1 - 54294967291autovarunsigned intint65531

在回答您的问题时,在这两种情况下,常量10 都会从转换intunsigned int

于 2013-02-11T18:31:53.640 回答