int y = -2147483648;
int z = unchecked(y / -1);
2 行目でOverflowException
. unchecked
これは防げないのでしょうか?
例えば:
int y = -2147483648;
int z = unchecked(y * 2);
例外は発生しません。
int y = -2147483648;
int z = unchecked(y / -1);
2 行目でOverflowException
. unchecked
これは防げないのでしょうか?
例えば:
int y = -2147483648;
int z = unchecked(y * 2);
例外は発生しません。
これは、C# コンパイラまたはジッターが制御できる例外ではありません。これは Intel/AMD プロセッサに固有のもので、IDIV 命令が失敗すると、CPU は #DE トラップ (Divide Error) を生成します。オペレーティング システムはプロセッサ トラップを処理し、STATUS_INTEGER_OVERFLOW 例外を使用してプロセスに反映します。CLR は、それを一致するマネージ例外に忠実に変換します。
インテル プロセッサー マニュアルは、それに関する情報の宝庫ではありません。
非整数の結果は 0 に向かって切り捨てられます (切り捨てられます)。剰余は常に除数より小さくなります。オーバーフローは、CF フラグではなく #DE (除算エラー) 例外で示されます。
英語: 符号付き除算の結果は +2147483648 であり、Int32.MaxValue + 1 であるため、intでは表現できません。それ以外の場合は、プロセッサが負の値を表す方法の必然的な副作用であり、2 の補数エンコーディングを使用します。これは、0 を表す単一の値を生成し、負の値と正の値を表す他の可能なエンコーディングの奇数を残します。負の値用にもう 1 つあります。と同じ種類のオーバーフロー-Int32.MinValue
ですが、プロセッサは NEG 命令でトラップせず、ガベージ結果を生成するだけです。
もちろん、この問題を抱えているのは C# 言語だけではありません。C# 言語仕様では、特別な動作に注意することで、実装定義の動作 (7.8.2 章) になっています。例外を処理するコードを生成することは、あまりにも非現実的であると考えられ、診断できないほど遅いコードを生成しました。C# の方法ではありません。
C および C++ 言語は、未定義の動作にすることで条件を上げています。これは、gcc または g++ コンパイラー (通常は MinGW ツールチェーンを使用) でコンパイルされたプログラムのように、本当に醜いものになる可能性があります。SEH の実行時サポートが不完全なため、例外を飲み込み、プロセッサが除算命令を再開できるようにします。プログラムがハングし、プロセッサが常に #DE トラップを生成して 100% のコアを消費します。分割を伝説的な停止と発火命令に変える:)
Section 7.72 (Division Operator) of the C# 4 specs states:
If the left operand is the smallest representable int or long value and the right operand is –1, an overflow occurs. In a checked context, [...]. In an unchecked context, it is implementation-defined as to whether a System.ArithmeticException (or a subclass thereof) is thrown or the overflow goes unreported with the resulting value being that of the left operand.
So the fact that this throws an exception in an unchecked context is not in fact a bug, since the behavior is implementation-defined.
C# 言語仕様 5.0のセクション 7.8.2 によると、次のケースがあります。
7.8.2 除算演算子
x / y 形式の演算の場合、特定の演算子の実装を選択するために、二項演算子オーバーロード解決 (§7.3.4) が適用されます。オペランドは選択した演算子のパラメーターの型に変換され、結果の型は演算子の戻り値の型になります。定義済みの除算演算子を以下に示します。すべての演算子は、x と y の商を計算します。
- 整数除算:
int operator /(int x, int y);
uint operator /(uint x, uint y);
long operator /(long x, long y);
ulong operator /(ulong x, ulong y);
右側のオペランドの値がゼロの場合、aSystem.DivideByZeroException
がスローされます。除算は、結果をゼロに丸めます。したがって、結果の絶対値は、2 つのオペランドの商の絶対値以下の最大の整数になります。2 つのオペランドが同じ符号を持つ場合、結果はゼロまたは正になり、2 つのオペランドが反対の符号を持つ場合、結果はゼロまたは負になります。左のオペランドが表現可能な最小の int または long 値で、右のオペランドが –1の場合、オーバーフローが発生します。チェックされたコンテキストでは、これによりSystem.ArithmeticException
(またはそのサブクラス) がスローされます。チェックされていないコンテキストでは、System.ArithmeticException
(またはそのサブクラス) がスローされるか、オーバーフローが報告されず、結果の値が左側のオペランドの値になります。