バイトがオーバーフローすると実際に何が起こりますか?
私たちが持っていると言う
byte byte1 = 150; // 10010110
byte byte2 = 199; // 11000111
今この追加を行う場合
byte byte3 = byte1 + byte2;
最終的にbyte3=94になると思いますが、実際にはどうなりますか?どういうわけか他のメモリを上書きしましたか、それともこれは完全に無害ですか?
とても簡単です。足し算をするだけで、8ビット以上の数字で外れます。9番目のビット(1つである)は「落ちる」だけで、残りの8ビットが残り、番号94を形成します。
(はい、無害です)
上位ビットは切り捨てられます。他のメモリに害を及ぼすことはなく、意図しない結果の観点からのみ害を及ぼします。
C#では
checked { byte byte3 = byte1 + byte2; }
オーバーフロー例外がスローされます。コードはunchecked
デフォルトでコンパイルされます。他の答えが言っているように、値は「ラップアラウンド」します。すなわち、byte3 = (byte1 + byte2) & 0xFF;
キャリーフラグが設定されます...しかし、期待どおりの結果が得られないことを除けば、悪影響はないはずです。
通常(正確な動作は言語とプラットフォームによって異なります)、結果はモジュロ256で取得されます。つまり、150 +199=349。349mod256=93。
これは他のストレージには影響しません。
質問にC#、C ++、Cのタグを付けたので、CとC++について回答します。C ++では、署名された型のオーバーフロー( C / C ++にsbyte
あると思います)を含めると、未定義の動作が発生します。signed char
ただし、byte
(unsigned char
C ++にある)などの符号なし型の場合、結果はモジュロ2 nになります。ここで、nは符号なし型のビット数です。C#では、2番目のルールが適用され、署名された型がブロック内にある場合は例外が生成されchecked
ます。C#の部分が間違っている可能性があります。
オーバーフローはc#では無害です-メモリをオーバーフローさせることはありません-結果の最後の8ビットを取得するだけです。これを例外にしたい場合は、「checked」キーワードを使用してください。また、byte + byteがintを与えることがあるので、byteにキャストバックする必要があるかもしれないことにも注意してください。
動作は言語によって異なります。
CおよびC++では、符号付きオーバーフローは未定義であり、符号なしオーバーフローは前述の動作をします(タイプはありませんがbyte
)。
C#では、キーワードを使用して、checked
オーバーフローが発生した場合に例外を受信することを明示的に指定し、キーワードを使用して、例外unchecked
を無視することを明示的に指定できます。
先頭ビットが落ちたところです。
そして、算術オーバーフローが発生します。150 + 199 = 349、バイナリ1 0101 1101であるため、上位1ビットはドロップされ、バイトは01011101になります。つまり、1バイトが保持できるビット数がオーバーフローしました。
損傷はありませんでした。たとえば、メモリが別の場所にオーバーフローしませんでした。
実際に何が起こるかを見てみましょう(Cでは(適切なデータ型があると仮定します。Cには「バイト」データ型がないという指摘もありますが、追加できる8ビットデータ型があります)) 。これらのバイトがスタックで宣言されている場合、それらはメインメモリに存在します。ある時点で、バイトは操作のためにプロセッサにコピーされます(プロセスやキャッシュなど、いくつかの重要な手順をスキップしています...)。プロセッサに入ると、それらはレジスタに格納されます。プロセッサは、これら2つのレジスタに対して加算操作を実行して、データを加算します。 ここで混乱の原因が発生します。 CPUは、ネイティブ(または場合によっては指定された)データ型で追加操作を実行します。CPUのネイティブタイプが32ビットワードであるとしましょう(そして、そのデータ型が追加操作に使用されるものです)。つまり、これらのバイトは、上位24ビットが設定されていない32ビットワードで格納されます。追加操作は、実際にターゲットの32ビットワードでオーバーフローを実行します。ただし、(これが重要なビットです)データがレジスタからスタックにコピーバックされると、最下位8ビット(バイト)のみがスタック上のターゲット変数の位置にコピーバックされます。(ここでも、バイトパッキングとスタックに複雑さが伴うことに注意してください。)
それで、これが結果です。追加によりオーバーフローが発生します(選択した特定のプロセッサ命令によって異なります)。ただし、データはプロセッサから適切なサイズのデータ型にコピーされるため、オーバーフローは認識されません(適切に記述されたコンパイラを想定すると、無害です)。
C#に関する限り、typeの2つの値を足しbyte
合わせると、typeの値が生成され、int
これをにキャストバックする必要がありbyte
ます。
したがって、コードサンプルでは、次のようにバイトにキャストバックせずにコンパイラエラーが発生します。
byte byte1 = 150; // 10010110
byte byte2 = 199; // 11000111
byte byte3 = (byte)(byte1 + byte2);
詳細については、MSDNを参照してください。また、C#言語仕様のセクション7.3.6数値プロモーションも参照してください。