[英]Convert unsigned int to signed int C
我正在嘗試將65529
從unsigned int
轉換為 signed 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
,我們不關心 sign ,因為它是unsigned
。 因此,當我們使用%d
打印出來時,我們使用所有 16 位,因此它被解釋為65529
。
要了解原因,您需要知道 CPU 使用二進制補碼(可能不是全部,但很多)來表示有符號數。
byte n = 1; //0000 0001 = 1
n = ~n + 1; //1111 1110 + 0000 0001 = 1111 1111 = -1
而且,類型 int 和 unsigned int 的大小可以根據您的 CPU 不同而不同。 在做這樣的特定事情時:
#include <stdint.h>
int8_t ibyte;
uint8_t ubyte;
int16_t iword;
//......
對於 16 位整數,值 65529u 和 -7 的表示是相同的。 只是位的解釋不同。
對於較大的整數和這些值,您需要對擴展進行簽名; 一種方法是邏輯運算
int y = (int )(x | 0xffff0000u); // assumes 16 to 32 extension, x is > 32767
如果速度不是問題,或者處理器上的除法速度很快,
int y = ((int ) (x * 65536u)) / 65536;
乘法左移 16 位(再次假設擴展為 16 到 32 位),而除法右移保持符號不變。
由於轉換無符號值用於表示正數,因此可以通過將最高有效位設置為 0 來完成轉換。因此程序不會將其解釋為二進制補碼值。 一個警告是,這將丟失接近無符號類型最大值的數字的信息。
template <typename TUnsigned, typename TSinged>
TSinged UnsignedToSigned(TUnsigned val)
{
return val & ~(1 << ((sizeof(TUnsigned) * 8) - 1));
}
我知道這是一個老問題,但我認為響應者可能誤解了它。 我認為其目的是將作為無符號整數(技術上, unsigned short
)接收到的 16 位位序列轉換為有符號整數。 當您需要將從網絡接收到的某些內容從網絡字節順序轉換為主機字節順序時,可能會發生這種情況(最近對我來說是這樣)。 在這種情況下,使用聯合:
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;
現在minus_seven
的值為-7。
您期望您的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);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.