signed int x = -5;
unsigned int y = x;
の値はy
? これはどうしてですか?
の最大値に依存しますunsigned int
。通常、aunsigned int
は 32 ビット長なので、UINT_MAX
は 2 32 − 1 です。C 標準 (§6.3.1.3/2) では、符号付き→符号なしの変換を次のように実行する必要があります。
それ以外の場合、新しい型が符号なしの場合、値が新しい型の範囲内になるまで、新しい型で表現できる最大値よりも 1 多い値を繰り返し加算または減算することによって、値が変換されます。
したがって、y = x + ((2 32 − 1) + 1) = 2 32 − 5 = 4294967291 です。
最近のほとんどの実装である 2 の補数プラットフォームでは、の2 の補数表現と同じです。y
x
-5 = ~5 + 1 = 0xFFFFFFFA + 1 = 0xFFFFFFFB = 4294967291.
C99 標準から:
6.3.1.3 符号付きおよび符号なし整数
- 整数型の値が _Bool 以外の別の整数型に変換される場合、その値が新しい型で表現できる場合、その値は変更されません。
- それ以外の場合、新しい型が符号なしの場合、値が新しい型の範囲内になるまで、新しい型で表現できる最大値よりも 1 多い値を繰り返し加算または減算することによって、値が変換されます。49)
49) ルールは、与えられたタイプの式の値ではなく、数学的な値の算術演算を記述します。
つまり、事実上、y = x + UINT_MAX + 1
.
これはたまたま、2 の補数表現が符号なし整数として変更されずに使用されることを意味します。これは、符号付き整数に 2 の補数を使用するため、ほとんどの最新のコンピューターで非常に高速になります。
の値y
はUINT_MAX - 5 + 1
、つまりUINT_MAX - 4
です。
符号付き整数値を符号なし型に変換すると、値は 2^N を法として減らされます。ここで、N は符号なし型の値を形成するビットの数です。これは、符号付きの負の値と正の値の両方に適用されます。
符号付き型から同じサイズの符号なし型に変換する場合、上記は、符号付きの正の値は変更されず (+5
に変換さ5
れるなど)、負の値は に追加されることを意味しますMAX + 1
。ここMAX
で、 は符号なし型の最大値です (-5
を取得します)。に変換されMAX + 1 - 5
ます)。
符号付きの値は通常、2の補数と呼ばれるものとして保存されます。
2の補数は、負の数を通常の2進数にエンコードする方法であり、加算は引き続き機能します。-1 + 1を加算すると0になりますが、通常の加算では、演算が符号ビットに特別な注意を払い、代わりに減算を実行しない限り、2または-2の結果が得られます。2の補数は、この余分なステップなしで正しい合計になります。
これは、メモリ内の-5と4294967291の実際の表現(32ビットワードの場合)が同一であることを意味します(例:0xFFFFFFFB
または。) 0b11111111111111111111111111111011
。だからあなたがするとき:
unsigned int y = x;
xの内容は逐語的に、つまりビット単位でにコピーされy
ます。これは、のメモリ内の生の値を検査するx
と、y
それらが同一になることを意味します。ただし、次の場合:
unsigned long long y1 = x;
の値はx
、unsignedlonglongに変換される前に符号拡張されます。long longが64ビットの一般的なケースでは、これはにy1
等しいことを意味し0xFFFFFFFFFFFFFFFB
ます。
より大きなタイプにキャストするとどうなるかに注意することが重要です。より大きな符号付きの値にキャストされる符号付きの値は、符号拡張されます。ソース値が符号なしの場合、これは発生しません。例:
unsigned int z = y + 5;
long long z1 = (long long)x + 5; // sign extended since x is signed
long long z2 = (long long)y + 5; // not sign extended since y is unsigned
z
そしてz1
0に等しくなりますが、そうでz2
はありません。これは、値を展開する前に署名済みにキャストすることで解決できます。
long long z3 = (long long)(signed int)y + 5;
または、符号拡張を発生させたくない場合は、同様に次のようにします。
long long z4 = (long long)(unsigned int)x;
y=0xfffffffb -5 (2 の補数) のバイナリ表現です。