web-dev-qa-db-ja.com

符号なしintを符号付きint Cに変換します

変換しようとしています65529からunsigned intから署名済みintへ。私はこのようなキャストをしようとしました:

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

ただし、yは、-7を返す必要があるときに65529を返します。何故ですか?

17
darksky

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>
32
Mysticial

私はそれが古い質問であることを知っていますが、それは良い質問です。これはどうですか?

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

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

@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として解釈されます。

4
JoeFish

理由を理解するには、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の拡張を想定)、除算は符号を維持しながら右にシフトします。

1
Doug Currie

int型の幅が16ビットであることが期待されています。この場合、実際には負の値が返されます。しかし、おそらく32ビット幅であるため、符号付きintは65529を適切に表すことができます。これを確認するには、sizeof(int)を印刷します。

0
Szabolcs

上記のコメントに投稿された質問に答えるには、次のようなものを試してください。

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
Throwback1986

符号なしの値の変換は正の数の変換を使用するため、最上位ビットを0に設定することで実行できます。したがって、プログラムはそれを2の補数値として解釈しません。 1つの注意点は、符号なし型の最大値に近い数の情報が失われることです。

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