セージ の メモ書き

メモこそ命の恩人だ

C# - オーバーフロー/アンダーフロー/checked キーワード

オーバーフロー/アンダーフロー

状態 内容
オーバーフロー 格納領域よりも大きい値を格納すること。
アンダーフロー 格納領域よりも小さい値を格納すること。
  • 上記の状態になると、正しく計算できない。
  • 上記の検出時、C# の場合は既定では例外が発生しない。
    • 上位ビットが破棄される。
    • 何事もないかのように処理される。
    • プロジェクトの設定を変更すれば検知できる。
  • 予期せぬ不具合になる恐れあり。

int の場合(-2147483648~2147483647)

var maxValue = int.MaxValue;
Debug.WriteLine($"{maxValue}, 0x{maxValue:x8}");
// 2147483647, 0x7fffffff
// int の最大値

maxValue += 1;
Debug.WriteLine($"{maxValue}, 0x{maxValue:x8}");
// -2147483648, 0x80000000
// 最大値よりも大きくしたが、例外は発生しなかった。


var minValue = int.MinValue;
Debug.WriteLine($"{minValue}, 0x{minValue:x8}");
// -2147483648, 0x80000000
// int の最小値

minValue -= 1;
Debug.WriteLine($"{minValue}, 0x{minValue:x8}");
// 2147483647, 0x7fffffff
// 最小値よりも小さくしたが、例外は発生しなかった。

uint の場合(0~4294967295)

var maxValue = uint.MaxValue;
Debug.WriteLine($"{maxValue}, 0x{maxValue:x8}");
// 4294967295, 0xffffffff
// uint の最大値

maxValue += 1;
Debug.WriteLine($"{maxValue}, 0x{maxValue:x8}");
// 0, 0x0
// 最大値よりも大きくしたが、例外は発生しなかった。


var minValue = uint.MinValue;
Debug.WriteLine($"{minValue}, 0x{minValue:x8}");
// 0, 0x00000000
// uint の最小値

minValue -= 1;
Debug.WriteLine($"{minValue}, 0x{minValue:x8}");
// 4294967295, 0xffffffff
// 最小値よりも小さくしたが、例外は発生しなかった。


プロジェクトの設定変更

  • プロジェクトのプロパティより、
    "詳細→算術オーバーフローのチェック" を有効にする。
  • 既定はチェックなし。
  • この方法の場合、プロジェクト全体で判定が行われる。
  • 後述の checked キーワードならば、部分的に判定できる。

checked キーワード

docs.microsoft.com

docs.microsoft.com

  • オーバーフロー/アンダーフローのチェックを有効にする。
  • 上記の検出時、System.OverflowException が発生する。
  • 以下の検出方法がある。
    • ブロック:checked { ~ }
    • 式:checked(***)

checked ブロック

checked
{
    var maxValue = int.MaxValue;
    maxValue += 1;
    // 例外が発生することを確認。
    // System.OverflowException: 'Arithmetic operation resulted in an overflow.'
}
checked
{
    var minValue = int.MinValue;
    minValue -= 1;
    // 例外が発生することを確認。
    // System.OverflowException: 'Arithmetic operation resulted in an overflow.'
}

checked 式

var maxValue = int.MaxValue;
var dummy = checked(maxValue + 1);
// 例外が発生することを確認。
// System.OverflowException: 'Arithmetic operation resulted in an overflow.'
var minValue = int.MinValue;
var dummy = checked(minValue - 1);
// 例外が発生することを確認。
// System.OverflowException: 'Arithmetic operation resulted in an overflow.'


豆知識

オーバーフローによる無限ループ

  • for文のインデックス用変数の範囲よりも、終了条件が大きいと無限ループする。
  • 以下、1バイトの領域で、300を終了条件にしたので、ループが終了しない。
  • こんな記述は普通しないが、やると無限ループする。
var count = 300;
for (byte i = 0; i < count; i++)
{
    Debug.WriteLine(i);
}
//0
//1
//2
//3
//...
//254
//255
//0
//1
//2
//3
//...



以上