整数型には扱える値の上限・下限があります。その範囲を超えた演算(オーバーフロー)が発生したとき、C# はデフォルトでは 例外を投げずに値を折り返す 動作をします。checked キーワードを使うと、オーバーフロー時に OverflowException をスローさせることができます。
デフォルトの動作(unchecked)
まずデフォルトの挙動を確認します。
int max = int.MaxValue; // 2147483647
int result = max + 1;
Console.WriteLine(result); // -2147483648
int.MaxValue + 1 は正の方向にオーバーフローし、折り返して int.MinValue(-2147483648)になります。例外は発生しません。
これはパフォーマンスを優先した C# のデフォルト設計です。意図しないオーバーフローが起きてもサイレントに通過するため、バグの原因になることがあります。
checked 式
checked(...) の形で式を囲むと、その演算でオーバーフローが起きた場合に OverflowException がスローされます。
int max = int.MaxValue;
try
{
int result = checked(max + 1);
Console.WriteLine(result);
}
catch (OverflowException ex)
{
Console.WriteLine($"オーバーフローが発生しました: {ex.Message}");
}
// → オーバーフローが発生しました: Arithmetic operation resulted in an overflow.
式単位で有効にできるため、特定の演算だけを保護したい場合に便利です。
checked ブロック
複数の演算をまとめて保護したい場合は、checked ブロックを使います。
checked
{
int a = int.MaxValue;
int b = a + 1; // OverflowException がスローされる
int c = b * 2; // こちらは実行されない
}
ブロック内のすべての整数演算が checked の対象になります。
unchecked キーワード
checked の逆が unchecked です。checked ブロックの中に unchecked ブロックを入れると、その部分だけオーバーフローチェックを無効化できます。
checked
{
int a = int.MaxValue;
// この演算だけ折り返しを許容する
int b = unchecked(a + 1);
Console.WriteLine(b); // -2147483648(例外なし)
}
また、既知の定数式でハッシュ計算など意図的に折り返しを使うケースでも unchecked が役立ちます。
// ハッシュ値の計算などで意図的に折り返しを使う例
int hash = unchecked(17 * 31 + someValue);
checked が対象とする型
checked が有効なのは 整数型の演算 に限られます。
| 型 | checked の対象 |
|---|---|
int, long, short, sbyte |
○ |
uint, ulong, ushort, byte |
○ |
float, double, decimal |
× |
| キャスト(整数型間) | ○ |
浮動小数点型(float / double)は IEEE 754 の仕様で Infinity や NaN を使うため、checked の対象外です。decimal も独自の例外処理を持つため対象外です。
キャストへの適用
整数型同士のキャストでも checked は有効です。
int large = 300;
// byte の範囲は 0〜255 なので 300 はオーバーフロー
byte b = checked((byte)large); // OverflowException がスローされる
デフォルトでは (byte)300 は 44(300 mod 256)になりますが、checked を使うと例外になります。
コンパイラオプション(CheckForOverflowUnderflow)
プロジェクト全体でオーバーフローチェックを有効にするには、.csproj に以下を追加します。
<PropertyGroup>
<CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
</PropertyGroup>
これを有効にすると、checked を書かなくても整数演算のオーバーフローで OverflowException がスローされます。
ただし、パフォーマンスに影響するため、通常のアプリケーションよりも数値計算の正確性が重要なドメイン(金融計算・科学計算など)での使用が多いです。
まとめ
| 構文 | 効果 |
|---|---|
checked(式) |
式単位でオーバーフローチェックを有効化 |
checked { ... } |
ブロック内の演算をすべてチェック対象に |
unchecked(式) |
式単位でオーバーフローチェックを無効化 |
unchecked { ... } |
ブロック内の演算をすべてチェック対象外に |
<CheckForOverflowUnderflow>true |
プロジェクト全体でチェックを有効化 |
デフォルトでは整数オーバーフローはサイレントに折り返すため、意図しない動作を防ぐために checked を積極的に活用しましょう。