我试图将65529
从unsigned int
转换为签名的int
。我尝试做这样的演员:
unsigned int x = 65529;
int y = (int) x;
但是当y
应该返回-7时仍然返回65529。这是为什么?
看起来你期待int
和unsigned int
是一个16位整数。显然情况并非如此。最有可能的是,它是一个32位整数 - 足够大,可以避免你所期望的环绕。
请注意,没有完全符合C的方法来执行此操作,因为在符号/无符号值之间进行超出范围的值是实现定义的。但在大多数情况下,这仍然有效:
unsigned int x = 65529;
int y = (short) x; // If short is a 16-bit integer.
或者:
unsigned int x = 65529;
int y = (int16_t) x; // This is defined in <stdint.h>
我知道这是一个老问题,但它是一个很好的问题,那么这个怎么样?
unsigned short int x = 65529U;
short int y = *(short int*)&x;
printf("%d\n", y);
@Mysticial得到了它。简短通常是16位,将说明答案:
int main()
{
unsigned int x = 65529;
int y = (int) x;
printf("%d\n", y);
unsigned short z = 65529;
short zz = (short)z;
printf("%d\n", zz);
}
65529
-7
Press any key to continue . . .
那么让我们看看65529十进制。它可以用十六进制表示为FFF9h
。我们也可以用二进制表示:
11111111 11111001
当我们声明short zz = 65529;
时,编译器将65529解释为有符号值。在二进制补码表示法中,最高位表示有符号值是正数还是负数。在这种情况下,您可以看到顶部位是1
,因此它被视为负数。这就是为什么它打印出-7
。
对于unsigned short
,我们不关心标志,因为它是unsigned
。因此,当我们使用%d
打印出来时,我们使用全部16位,因此它被解释为65529
。
要了解原因,您需要知道CPU使用二进制补码表示有符号数(可能不是全部,而是很多)。
byte n = 1; //0000 0001 = 1
n = ~n + 1; //1111 1110 + 0000 0001 = 1111 1111 = -1
而且,根据您的CPU,int和unsigned int类型的大小可以不同。在做这样的具体事情时:
#include <stdint.h>
int8_t ibyte;
uint8_t ubyte;
int16_t iword;
//......
对于16位整数,值65529u和-7的表示相同。只有比特的解释是不同的。
对于较大的整数和这些值,您需要签署extend;一种方式是逻辑运算
int y = (int )(x | 0xffff0000u); // assumes 16 to 32 extension, x is > 32767
如果速度不是问题,或者处理器上的分频很快,
int y = ((int ) (x * 65536u)) / 65536;
乘法左移16位(再次假设16到32扩展),并且右移保持符号。
你期望你的int
类型是16位宽,在这种情况下你确实得到一个负值。但很可能它是32位宽,所以签名的int
可以代表65529就好了。你可以通过打印sizeof(int)
来检查。
要回答上面评论中发布的问题,请尝试以下方法:
unsigned short int x = 65529U;
short int y = (short int)x;
printf("%d\n", y);
要么
unsigned short int x = 65529U;
short int y = 0;
memcpy(&y, &x, sizeof(short int);
printf("%d\n", y);
由于转换无符号值用于表示正数转换,可以通过将最高有效位设置为0来完成。因此,程序不会将其解释为二进制补码值。需要注意的是,对于接近最大无符号类型的数字,这将丢失信息。
template <typename TUnsigned, typename TSinged>
TSinged UnsignedToSigned(TUnsigned val)
{
return val & ~(1 << ((sizeof(TUnsigned) * 8) - 1));
}