C ++隐式数据类型从unsigned转换为signed

时间:2013-02-11 17:50:06

标签: c++ types

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

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

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

4 个答案:

答案 0 :(得分:4)

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

结果(减法)是无符号的,然后进入溢出状态,结果是“比溢出0小5个数字”(4294967291 = 2 32 -5)

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

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

答案 1 :(得分:3)

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

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

在第二种情况下,表达式的类型(同样,unsigned)成为变量的类型,使用无符号值初始化而没有任何溢出。

答案 2 :(得分:2)

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

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

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

答案 3 :(得分:1)

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

int var = 5u - 10;

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

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

auto var = 5u - 10;

5u - 10的评估方式与之前相同,导致系统unsigned int或[{1}}的结果为UINT_MAX + 1 - 54294967291表示auto采用表达式var的类型,因此不会执行转换。 (在具有16位unsigned int的系统上,结果为int。)

在回答您的问题时,在两种情况下,常量65531 10转换为int