int a = -534;
unsigned int b = (unsigned int)a;
printf("%d, %d", a, b);
打印-534, -534
为什么没有发生类型转换?
我预计它会-534, 534
如果我将代码修改为
int a = -534;
unsigned int b = (unsigned int)a;
if(a < b)
printf("%d, %d", a, b);
它没有打印任何内容......毕竟a
小于b
??
答案 0 :(得分:15)
因为您使用%d
进行打印。使用%u
表示未签名。由于printf是一个vararg函数,它不能知道参数的类型,而必须依赖于格式说明符。因此,你所做的类型转换没有效果。
答案 1 :(得分:4)
printf中的说明符要求printf打印有符号整数,因此底层字节被解释为有符号整数。
您应该使用%u
指定您想要无符号整数。
编辑 a==b
对于比较是正确的,这是奇怪的行为,但它完全有效。您没有更改基础位,只是要求编译器以某种方式处理基础位。因此,按位比较结果为真。
[speculation]
我怀疑在编译器实现中行为可能会有所不同 - 例如,虚构的CPU可能不会对有符号和无符号数字使用相同的逻辑,在这种情况下,按位比较会失败。 [/speculation]
答案 2 :(得分:4)
首先,您不需要演员:a
的值隐含地转换为unsigned int
,并赋值给b
。所以你的陈述相当于:
unsigned int b = a;
现在,C和C ++中unsigned
整数类型的一个重要属性是它们的值始终在[0, max ]范围内,其中 max unsigned int
为UINT_MAX
(在limits.h
中定义)。如果指定的值不在该范围内,则会转换为该范围。因此,如果值为负,则重复添加UINT_MAX+1
以使其在[0,UINT_MAX
]范围内。对于上面的代码,就好像我们写了:unsigned int b = (UINT_MAX + a) + 1
。这不等于-a
(534)。
注意,无论底层表示是二进制补码,一是补码还是符号幅度(或任何其他外来编码),上述情况都是正确的。人们可以通过以下方式看到:
signed char c = -1;
unsigned int u = c;
printf("%u\n", u);
assert(u == UINT_MAX);
在具有4字节int
的典型二进制补码机器上,c
为0xff
,u
为0xffffffff
。编译器必须确保在将值-1
分配给u
时,将其转换为等于UINT_MAX
的值。
现在回到您的代码,printf
格式字符串对b
是错误的。您应该使用%u
。当您这样做时,您会发现它打印的值为UINT_MAX - 534 + 1
而不是534
。
在比较运算符<
中使用时,由于b
为unsigned int
,a
也会转换为unsigned int
。这是b = a
给出的;之前,表示a < b
为假:a
,因为unsigned int
等于b
。
假设您有一台补充机器,您可以:
signed char c = -1;
unsigned char uc = c;
假设char
(有符号或无符号)在该机器上是8位。然后c
和uc
将存储以下值和位模式:
+----+------+-----------+
| c | -1 | 11111110 |
+----+------+-----------+
| uc | 255 | 11111111 |
+----+------+-----------+
请注意c
和uc
的位模式不一样。编译器必须确保c
的值为-1
,而uc
的值为UCHAR_MAX
,在此计算机上为255。
答案 3 :(得分:1)
你想要的行为似乎是由函数abs提供的:
int a = -534;
int b = abs(a);
printf("%d, %d", a, b);
答案 4 :(得分:0)
我想第一个为什么b被打印为-534的情况已被Tronic和Hassan充分回答。你不应该使用%d并且应该使用%u。
就你的第二个案例而言,同样会发生一个隐式的类型转换,a和b都是相同的,因为你的比较会产生预期的结果。
答案 5 :(得分:0)
据我所知,if失败是因为编译器假定第二个变量应该被认为是与第一个变量相同的类型。尝试 if(b&gt; a) 看到差异。
答案 6 :(得分:0)
第二个问题:
比较从不在两种不同的类型之间起作用 - 它们总是隐式地转换为“最小公分母”,在这种情况下将是unsigned int
。我知道,讨厌和反直觉。
答案 7 :(得分:0)
将整数类型从signed转换为unsigned不会修改位模式,它只会更改位模式的解释。
你也有一个格式说明符不匹配,%u应该用于无符号整数,但即便如此,结果也不会像你期望的那样是534,而是4294966762。
如果你想使负值为正,只需否定它:
unsigned b = (unsigned)-a ;
printf("%d, %u", a, b);
对于第二个例子,具有不同签名的类型之间的操作涉及神秘的隐式转换规则 - 避免。您应该将编译器的警告级别设置为高以捕获许多这些错误。我建议用VC ++中的/ W4 / WX和-Wall -Werror -Wformat for GCC。