おそらく、番号 18446744073692774400 を生成するために何が起こったのかを説明する価値があります。技術的に言えば、記述した式は「未定義の動作」をトリガーするため、コンパイラーは結果として何かを生成する可能性があります。ただし、 が 32 ビット型であると仮定int
すると、最近ではほぼ常にそうですが、
uint64_t x = (int) (255u*256u*256u*256u);
その式は未定義の動作をトリガーしません。unsigned int
( からへの変換にint
は実装定義の動作が含まれますが、1 の補数または符号と大きさの CPU は何年にもわたって作成されていないため、遭遇する可能性が高いすべての実装でまったく同じ方法で定義されています。)ここで述べていることはすべて、C と C++ に等しく適用されるためです。
まず、乗算を見てみましょう。右辺を 16 進数で書いているのは、その方が何が起こっているかを簡単に確認できるからです。
255u * 256u = 0x0000FF00u
255u * 256u * 256u = 0x00FF0000u
255u * 256u * 256u * 256u = 0xFF000000u (= 4278190080)
その最後の結果 に0xFF000000u
は、32 ビットの数値セットの最上位ビットがあります。したがって、その値を符号付き32 ビット型にキャストすると、あたかも 2 32が減算されたかのように負の値になります (これは、前述の実装定義の操作です)。
(int) (255u*256u*256u*256u) = 0xFF000000 = -16777216
値を符号付き型に変換しても値のビット パターンが変わらないことu
を強調するために、サフィックスなしで16 進数をそこに書きます。再解釈されるだけです。
これで、変数に -16777216 を代入すると、 2 64uint64_t
を追加することで符号なし as-if に逆変換されます。(符号なしから符号付きへの変換とは異なり、このセマンティクスは標準で規定されています。)これはビット パターンを変更し、数値の上位 32 ビットをすべて 0 ではなく 1 に設定します。
(uint64_t) (int) (255u*256u*256u*256u) = 0xFFFFFFFFFF000000u
10 進数で書く0xFFFFFFFFFF000000
と、18446744073692774400 になります。
最後のアドバイスとして、C または C++ から「不可能な」整数を取得した場合は、16 進数で出力してみてください。2 の補数の固定幅演算の奇妙さをそのように見る方がはるかに簡単です。