この章のテーマ §
checkedステートメント、uncheckedステートメントと、checked/uncheckedを式中で使用した場合の動作を学びます。また、checkedコンテキスト/uncheckedコンテキストについても学びます。
前提知識 §
Console.Writeメソッド, Console.WriteLineメソッド, 文字列の基礎, 変数の基礎, 例外の基礎, int型, float型, 複文, try-catch構文
解説 §
これらの機能は、整数のオーバーフローのチェックの制御のために存在します。
checked文の次に書かれた文は、整数計算がオーバーフローを起こすとOverflowExceptionの例外が発生します。
uncheckedの次に書かれた文は、整数計算がオーバーフローを起こしても、例外は発生させずに誤った結果のまま処理を継続します。
これらの文の次の文は複文やメソッド呼び出しなどにできますので、複数の文に影響を及ぼせます。この影響の及ぶ文脈をcheckedコンテキスト/uncheckedコンテキストと呼ぶこともあります。
checked/uncheckedは式の中で使用することができ、式の一部だけ動作を変えることができます。
なぜチェックしないuncheckedが存在するのでしょうか?
理由はいくつかあります。
- uncheckedの方が高速。オーバーフローがないと見切れているときはこちらの方が性能的に有利
- 計算間違いが重要ではないとき。ゲームなどで結果の正しが重視されないことがある
- 互換性のため。古いC言語などでは、オーバーフローで例外を起こす機能を持っていないので、同じようなコードをC#で実行する場合はオーバーフローを起こさない方が有利
- 計算の間違いを見越した使い方をされることがある。たとえばbyte型は255に1を足すと0になってしまい計算としては間違いだが、0から255のカウントを繰り返す処理には便利なので利用される場合がある
罠の数々 §
- 何も指定されない初期状態ではunchecked
- checked/uncheckedは、浮動小数点型には影響しない
- checked/uncheckedは、ゼロ除算には影響しない。整数のゼロ除算は常に例外を発生させる
参考リンク §
Checked と Unchecked (C# リファレンス)
サンプルソース: kw_checked_unchecked §
int max = int.MaxValue;
int min = int.MinValue;
int zero = 0;
float maxf = float.MaxValue;
float minf = float.MinValue;
Console.WriteLine("unchecked context");
unchecked
{
sub("int.MaxValue+1", () => max + 1);
sub("int.MinValue-1", () => min - 1);
sub("float.MaxValue+1", () => maxf + 1);
sub("float.MinValue-1", () => minf - 1);
sub("1/0", () => 1 / zero);
}
Console.WriteLine("checked context");
checked
{
sub("int.MaxValue+1", () => max + 1);
sub("int.MinValue-1", () => min - 1);
sub("float.MaxValue+1", () => maxf + 1);
sub("float.MinValue-1", () => minf - 1);
sub("1/0", () => 1 / zero);
}
Console.WriteLine("checked under unchecked context");
unchecked
{
sub("int.MaxValue+1", checked(() => max + 1));
sub("int.MinValue-1", checked(() => min - 1));
}
Console.WriteLine("unchecked under checked context");
checked
{
sub("int.MaxValue+1", unchecked(() => max + 1));
sub("int.MinValue-1", unchecked(() => min - 1));
}
void sub<T>(string name, Func<T> expression)
{
Console.Write(name);
Console.Write(" ");
try
{
var r = expression();
Console.WriteLine($"計算終了: {r}");
}
catch (OverflowException)
{
Console.WriteLine("OverflowException例外発生!");
}
catch (Exception e)
{
Console.WriteLine($"その他の例外発生! {e.GetType().Name}");
}
}
実行結果 §
unchecked context
int.MaxValue+1 計算終了: -2147483648
int.MinValue-1 計算終了: 2147483647
float.MaxValue+1 計算終了: 3.4028235E+38
float.MinValue-1 計算終了: -3.4028235E+38
1/0 その他の例外発生! DivideByZeroException
checked context
int.MaxValue+1 OverflowException例外発生!
int.MinValue-1 OverflowException例外発生!
float.MaxValue+1 計算終了: 3.4028235E+38
float.MinValue-1 計算終了: -3.4028235E+38
1/0 その他の例外発生! DivideByZeroException
checked under unchecked context
int.MaxValue+1 OverflowException例外発生!
int.MinValue-1 OverflowException例外発生!
unchecked under checked context
int.MaxValue+1 計算終了: -2147483648
int.MinValue-1 計算終了: 2147483647
リポジトリ §
https://github.com/autumn009/CSharpPrimer2
練習問題 §
以下のプログラムの実行結果を予測してみよう。
int a = 1;
unchecked
{
checked
{
Console.WriteLine(int.MaxValue+a);
}
}
- checkedステートメントの影響下で動作しているのだから例外が起きる
- uncheckedステートメントの影響下で動作しているのだから例外が起きない
- checkedステートメントとuncheckedステートメントの両方の影響下で動作しているのだから例外は起きないが同時に例外は起きる
[[解答]]