将unsigned int转换为signed int C.

时间:2011-11-29 20:29:04

标签: c int unsigned-integer

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

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

但是当y返回-7时,{{1}}仍然返回65529。那是为什么?

9 个答案:

答案 0 :(得分:30)

您似乎期望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>

答案 1 :(得分:5)

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

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

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

答案 2 :(得分: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 . . .

<小时/> 更多细节。这都是关于签名号码如何存储在内存中的。搜索二进制补码表示法以获取更多细节,但这是基础知识。

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

11111111 11111001

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

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

答案 3 :(得分: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;
   //......

答案 4 :(得分: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扩展),并且右移保持符号。

答案 5 :(得分:0)

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

答案 6 :(得分: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);

答案 7 :(得分:0)

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

template <typename TUnsigned, typename TSinged>
TSinged UnsignedToSigned(TUnsigned val)
{
    return val & ~(1 << ((sizeof(TUnsigned) * 8) - 1));
}

答案 8 :(得分:0)

我知道这是一个老问题,但是我认为响应者可能会误解它。我认为打算将以无符号整数(技术上为structure(list(Quarter = structure(1:15, .Label = c("2016 Q2", "2016 Q3", "2016 Q4", "2017 Q1", "2017 Q2", "2017 Q3", "2017 Q4", "2018 Q1", "2018 Q2", "2018 Q3", "2018 Q4", "2019 Q1", "2019 Q2", "2019 Q3", "2019 Q4"), class = "factor"), Freq = c(89, 1401, 1303, 1205, 1620, 2019, 1632, 1664, 1755, 1708, 1408, 1533, 2075, 2262, 1408)), row.names = c(NA, -15L), class = "data.frame") )接收的16位比特序列转换为有符号整数。当您需要将从网络接收的内容从网络字节顺序转换为主机字节顺序时,可能会发生这种情况(最近发生在我身上)。在这种情况下,请使用并集:

unsigned short

现在unsigned short value_from_network; unsigned short host_val = ntohs(value_from_network); // Now suppose host_val is 65529. union SignedUnsigned { short s_int; unsigned short us_int; }; SignedUnsigned su; su.us_int = host_val; short minus_seven = su.s_int; 的值为-7。