将unsigned int转换为signed int C.

问题描述 投票:16回答:8

我试图将65529unsigned int转换为签名的int。我尝试做这样的演员:

unsigned int x = 65529;
int y = (int) x;

但是当y应该返回-7时仍然返回65529。这是为什么?

c int unsigned-integer
8个回答
31
投票

看起来你期待intunsigned 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>

6
投票

我知道这是一个老问题,但它是一个很好的问题,那么这个怎么样?

unsigned short int x = 65529U;
short int y = *(short int*)&x;

printf("%d\n", y);

4
投票

@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 . . .


A little more detail. It's all about how signed numbers are stored in memory. Do a search for twos-complement notation for more detail, but here are the basics.

那么让我们看看65529十进制。它可以用十六进制表示为FFF9h。我们也可以用二进制表示:

11111111 11111001

当我们声明short zz = 65529;时,编译器将65529解释为有符号值。在二进制补码表示法中,最高位表示有符号值是正数还是负数。在这种情况下,您可以看到顶部位是1,因此它被视为负数。这就是为什么它打印出-7

对于unsigned short,我们不关心标志,因为它是unsigned。因此,当我们使用%d打印出来时,我们使用全部16位,因此它被解释为65529


2
投票

要了解原因,您需要知道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;
   //......

1
投票

对于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扩展),并且右移保持符号。


0
投票

你期望你的int类型是16位宽,在这种情况下你确实得到一个负值。但很可能它是32位宽,所以签名的int可以代表65529就好了。你可以通过打印sizeof(int)来检查。


0
投票

要回答上面评论中发布的问题,请尝试以下方法:

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
投票

由于转换无符号值用于表示正数转换,可以通过将最高有效位设置为0来完成。因此,程序不会将其解释为二进制补码值。需要注意的是,对于接近最大无符号类型的数字,这将丢失信息。

template <typename TUnsigned, typename TSinged>
TSinged UnsignedToSigned(TUnsigned val)
{
    return val & ~(1 << ((sizeof(TUnsigned) * 8) - 1));
}
© www.soinside.com 2019 - 2024. All rights reserved.