変換しようとしています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 . . .
10進数の65529を見てみましょう。 16進数でFFF9h
として表すことができます。また、次のようにバイナリで表すこともできます。
11111111 11111001
short zz = 65529;
を宣言すると、コンパイラは65529を符号付き値として解釈します。 2の補数表記では、最上位ビットは符号付きの値が正か負かを示します。この場合、最上位ビットは1
であることがわかるため、負の数として扱われます。それが-7
を出力する理由です。
unsigned short
の場合、unsigned
であるため、符号は重要ではありません。したがって、%d
を使用して出力する場合、16ビットすべてを使用するため、65529
として解釈されます。
理由を理解するには、CPUが2の補数(すべてではなく、多くの場合)を使用して符号付き数値を表すことを知る必要があります。
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;
//......
値65529uおよび-7の表現は、16ビット整数に対して同一です。ビットの解釈のみが異なります。
より大きな整数とこれらの値の場合、拡張に署名する必要があります。 1つの方法は論理演算です
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に設定することで実行できます。したがって、プログラムはそれを2の補数値として解釈しません。 1つの注意点は、符号なし型の最大値に近い数の情報が失われることです。
template <typename TUnsigned, typename TSinged>
TSinged UnsignedToSigned(TUnsigned val)
{
return val & ~(1 << ((sizeof(TUnsigned) * 8) - 1));
}