2

重複の可能性:
符号なし変数に負の値を割り当てるとどうなりますか?

私はC++を初めて使用し、符号なし型の使用方法を知りたいです。型については、unsigned int0から4294967296までの値を取ることができることを知っています。しかし、unsignedint型を次のように初期化する場合:

unsigned int x = -10;
cout << x;

出力は、4294967286 これを取得したようoutput = max value - 10です。だから私は記憶の中で何が起こっているのか知りたいですか?この計算を続けている間、どのようなプロセスが実行されていますか?回答ありがとうございます。

4

3 に答える 3

6

ラップアラウンド動作が発生しています。

符号なし型は循環的です(一方、符号付き型は循環的である場合とそうでない場合がありますが、信頼すべきではない未定義の動作です)。つまり、可能な最小値より1つ小さい値が、可能な最大値です。次のスニペットを使用して、これを自分で示すことができます。

int main()
{
    unsigned int x = 5;
    for (int i = 0; i < 10; ++i) cout << x-- << endl;
    return 0;
}

ゼロに達した後、xの値が表現可能な最大値である2^32-1にジャンプすることに気付くでしょう。さらに減算すると、期待どおりに機能します。

符号なし0から1を引くと、ビットパターンは次のように変化します。

0000 0000 0000 0000 0000 0000 0000 0000 // before (0)
1111 1111 1111 1111 1111 1111 1111 1111 // after  (2^32 - 1)

符号なしの数値では、負の数値はゼロから減算された正の数値のように扱われます。したがって、(unsigned int) -10に等しくなり((unsigned int) 0) - ((unsigned int) 10)ます。

私はそれをunsignedintがより高精度の任意の値の下位32ビットであると考えるのが好きです。このような:

v imaginary high order bit
1 0000 0000 0000 0000 0000 0000 0000 0000 // before (2^32)
0 1111 1111 1111 1111 1111 1111 1111 1111 // after  (2^32 - 1)

これらのオーバーフローの場合のunsignedintの動作は、256から1を引いたときのunsigned intの下位8ビットの動作とまったく同じです。このようにunsignedchar(1バイト)を見る方が理にかなっています。unsigned char制限された精度が余分なビットを破棄するため、にキャストされた場合、値0と256は等しいためです。

0 0000 0000 0000 0000 0000 0001 0000 0000 // before (256)
0 0000 0000 0000 0000 0000 0000 1111 1111 // before (255)

他の人が指摘しているように、これはモジュロ算術と呼ばれます。高精度の値を使用して、高次のビットをマスクするため、ラップアラウンド時に行われる遷移を視覚化するのに役立ちます。それが何であったかは関係ないので、それは何でもかまいません、それはただ捨てられます。整数はモジュラス2^32を超える値であるため、2^32の倍数は整数のスペースでゼロに等しくなります。だから私は最後に余分なビットがあるふりをして逃げることができます。

次のステートメントで使用されているように、プログラムで2 ^ 32以外の数値を計算する必要がある場合に備えて、モジュラス演算には専用の演算子があります。

int forty_mod_twelve = 40 % 12;
// value is 4: 4 + n * 12 == 40 for some whole number n

2の累乗(2 ^ 32など)でのモジュラス演算は、上位ビットをマスクするように直接単純化されます。64ビット整数を2 ^ 32を法として計算すると、値は変換した場合とまったく同じになります。符号なし整数に。

01011010 01011100 10000001 00001101 11111111 11111111 11111111 11111111 // before
00000000 00000000 00000000 00000000 11111111 11111111 11111111 11111111 // after

プログラマーは、このプロパティを使用してプログラムを高速化することを好みます。これは、いくつかのビットを簡単に切り落とすことができるためですが、モジュラス演算の実行ははるかに困難です(除算を実行するのと同じくらい困難です)。

それは理にかなっていますか?

于 2012-10-08T17:40:23.723 に答える
4

これには、標準の積分変換が含まれます。適用されるルールは次のとおりです。リテラルの型から始め10ます。

2.14.2 整数リテラル [lex.icon]

整数リテラルは、ピリオドまたは指数部を持たない一連の数字です。整数リテラルには、その基数を指定する接頭辞とその型を指定する接尾辞を付けることができます。一連の数字の字句的に最初の数字が最も重要です。10 進整数リテラル (基数 10) は、10 進数以外の数字で始まり0、一連の 10 進数で構成されます。8 進整数リテラル (基数 8) は数字で始まり0、一連の 8 進数字で構成されます。16 進整数リテラル (基数 16) は、0xor0Xで始まり、一連の 16 進数で構成されます。これには、10 進数字と文字が含まafますAF10 から 15 までの 10 進数値を使用します。[例: 12 という数字は、、、、または と書くことが12でき014ます0XC。— 終了例 ]

整数リテラルの型は、その値を表すことができる表 6 の対応するリストの最初のものです。

次の表は、最初のタイプでintあり、適合します。したがって、リテラルの型はintです。

型を変更しない単項マイナス演算子が適用されます。次に、次のルールが適用されます。

4.7 積分変換 [conv.integral]

整数型の prvalue は、別の整数型の prvalue に変換できます。スコープのない列挙型の prvalue は、整数型の prvalue に変換できます。

宛先の型が符号なしの場合、結果の値は、ソースの整数と一致する最小の符号なし整数になります (モジュロ 2 nで、n は符号なしの型を表すために使用されるビット数です)。[ 注: 2 の補数表現では、この変換は概念的なものであり、ビット パターンに変更はありません (切り捨てがない場合)。— エンドノート]

于 2012-10-08T17:34:02.697 に答える
0

値をそのまま出力する代わりに、16 進形式で出力します (申し訳ありませんが、cout でそれを行う方法を忘れましたが、それが可能であることはわかっています)。両方の値の表現が同じであることがわかります。

あなたのコンテキストから、整数は 32 ビットです (これは必ずしもそうではありません)。符号付き整数を使用する場合、最上位ビットは符号であり、値の一部ではありません。符号なし整数を使用する場合、最上位ビットは値の一部です。

于 2012-10-08T17:35:29.147 に答える