类型转换为C中的unsigned

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 ??

首先,您不需要强制转换:a的值隐式转换为unsigned int ,赋值为b 。 所以你的陈述相当于:

 unsigned int b = a; 

现在,C和C ++中unsigned整数类型的一个重要特性是它们的值总是在[0, max ]范围内,其中unsigned int maxUINT_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的典型二进制补码机器上, c0xffu0xffffffff 。 编译器必须确保当为-1分配值-1时,它将转换为等于UINT_MAX的值。

现在回到你的代码, bprintf格式字符串是错误的。 你应该使用%u 。 当你这样做时,你会发现它打印的值为UINT_MAX - 534 + 1而不是534

当在比较运算符< ,由于bunsigned inta也会转换为unsigned int 。 这个,用b = a给出; 之前,表示a < b为false: a作为unsigned int等于b

假设您有一台补充机器,您可以:

 signed char c = -1; unsigned char uc = c; 

假设char (有符号或无符号)在该机器上是8位。 然后cuc将存储以下值和位模式:

 +----+------+-----------+ | c | -1 | 11111110 | +----+------+-----------+ | uc | 255 | 11111111 | +----+------+-----------+ 

注意cuc的位模式不一样。 编译器必须确保c的值为-1 ,并且uc的值为UCHAR_MAX ,在此计算机上为255。

关于我在SO上的问题的答案有更详细的说明。

因为您使用%d进行打印。 使用%u表示未签名。 由于printf是一个vararg函数,它无法知道参数的类型,而必须依赖于格式说明符。 因此,你所做的类型转换没有效果。

printf中的说明符要求printf打印有符号整数,因此底层字节被解释为有符号整数。

您应该使用%u指定您想要无符号整数。

编辑: a==b对于比较是真的,这是奇怪的行为,但它完全有效。 您没有更改基础位,只是要求编译器以某种方式处理基础位。 因此,按位比较产生真实。

[speculation]我怀疑编译器实现之间的行为可能会有所不同 – 虚拟CPU可能不会对有符号和无符号数字使用相同的逻辑,在这种情况下,按位比较会失败。 [/speculation]

C有时可能是一头丑陋的野兽。 问题是-534始终表示值0xfffffdea是否存储在unsigned int或signed int类型的变量中。 要比较这些变量,它们必须是相同的类型,因此将自动转换为unsigned或signed int以匹配另一个。 一旦它们是相同类型,它们就相同,因为它们代表相同的值。

似乎你想要的行为是由函数abs提供的:

 int a = -534; int b = abs(a); printf("%d, %d", a, b); 

我想第一个为什么b被打印为-534的情况已被Tronic和Hassan充分回答。 您不应该使用%d并且应该使用%u。

就你的第二个案例而言,同样会发生隐式类型转换,a和b都是相同的,因为你的比较会产生预期的结果。

如我所见,if失败,因为编译器假定第二个变量应该被认为是与第一个变量相同的类型。 尝试if(b> a)来看看差异。

第二个问题:比较永远不会在两种不同的类型之间起作用 – 它们总是隐式地转换为“最小公分母”,在这种情况下它将是unsigned int 。 我知道,讨厌和反直觉。

将有符号转换为无符号的整数类型不会修改位模式,它只会更改位模式的解释。

你也有一个格式说明符不匹配,%u应该用于无符号整数,但即便如此,结果也不会像你期望的那样是534,而是4294966762。

如果你想使负值正,只需否定它:

 unsigned b = (unsigned)-a ; printf("%d, %u", a, b); 

至于第二个例子,具有不同签名的类型之间的操作涉及神秘的隐式转换规则 – 避免。 您应该将编译器的警告级别设置为高以捕获许多这些错误。 我建议VC ++中的/ W4 / WX和GCC的-Wall -Werror -Wformat例如。