我知道较低的数据类型会被转换为更高的数据类型(例如int - > unsigned int - > float - >等)但我不确定以下内容:
int var = 5u - 10; // var = -5
auto var = 5u - 10; // var = 4294967291
5u是无符号的,但在第一种情况下为什么-10(有符号整数)没有转换为无符号值,而在第二种情况下呢?在第一种情况下,有符号值不会转换为无符号值,这对我来说很奇怪
答案 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 - 5
。 4294967291
表示auto
采用表达式var
的类型,因此不会执行转换。 (在具有16位unsigned int
的系统上,结果为int
。)
在回答您的问题时,在两种情况下,常量65531
从10
转换为int
。