C#の場合、以下のようにデフォルトでは整数型のオーバーフローチェックは行われません。
using System;
class Sample {
static void Main()
{
int a = int.MaxValue;
int b = 2;
int c = a * b; // ここでオーバーフローが起こるが、例外などはスローされない
Console.WriteLine("{0} * {1} = {2}", a, b, c);
}
}
D:\>csc sample.cs && sample.exe 2147483647 * 2 = -2
オーバーフローのチェック動作を変更するには、/checkedコンパイルオプションを指定するか、コード上でcheckedステートメントを使用します。 これはプリミティブ整数型にのみ有効なオプションです。
/checkedコンパイルオプション
整数型のオーバーフローをチェックするようにするには、コンパイル時に/checked+オプションを指定します。 チェックが有効な場合、オーバーフローが起こるとOverflowExceptionがスローされるようになります。
using System;
class Sample {
static void Main()
{
int a = int.MaxValue;
int b = 2;
// ここでオーバーフローが起こる
// オプション/checked+を付けてコンパイルする(オーバーフローをチェックするオプションを有効にする)と
// 例外OverflowExceptionがスローされるようになる
int c = a * b;
Console.WriteLine("{0} * {1} = {2}", a, b, c);
}
}
D:\>csc /checked+ sample.cs && sample.exe ハンドルされていない例外: System.OverflowException: 算術演算の結果オーバーフローが発生しました。 場所 Sample.Main()
このオプションを指定しないか、/checked-
を指定するとデフォルトの動作となり、オーバーフローをチェックしないようになります。
プロジェクトファイルでこのオプションを設定する場合は、CheckForOverflowUnderflowプロパティで設定します。
checkedステートメント
/checked
オプションとは別に、コード上でcheckedステートメントもしくはuncheckedステートメントを使用することもできます。 checked
ステートメント内では、コンパイルオプション/checked+
・/checked-
の指定にかかわらず、オーバーフローのチェックを強制することができます。
using System;
class Sample {
static void Main()
{
int a = int.MaxValue;
int b = 2;
// このブロックの中では、コンパイルオプションの指定に関わらずオーバーフローのチェックを強制する
checked {
int c = a * b;
Console.WriteLine("{0} * {1} = {2}", a, b, c);
}
}
}
D:\>csc /checked- sample.cs && sample.exe ハンドルされていない例外: System.OverflowException: 算術演算の結果オーバーフローが発生しました。 場所 Sample.Main()
逆にunchecked
ステートメント内ではオーバーフローのチェックを抑止できます。
using System;
class Sample {
static void Main()
{
int a = int.MaxValue;
int b = 2;
// このブロックの中では、コンパイルオプションの指定に関わらずオーバーフローのチェックを抑止する
unchecked {
int c = a * b;
Console.WriteLine("{0} * {1} = {2}", a, b, c);
}
}
}
D:\>csc /checked+ sample.cs && sample.exe 2147483647 * 2 = -2
演算子形式のchecked/unchecked
checked
/unchecked
は、次の例のように演算子の形式でも使用できます。
using System;
class Sample {
static void Main()
{
int a = int.MaxValue;
int b = 2;
// 演算に際してオーバーフローのチェックを抑止する
int c = unchecked(a * b);
Console.WriteLine("{0} * {1} = {2}", a, b, c);
}
}
D:\>csc /checked+ sample.cs && sample.exe 2147483647 * 2 = -2
int同士の積をオーバーフローさせずに求めるにはMath.BigMulメソッドを使用することも出来ます。 詳しくは数学関数 §.積・商と剰余 (BigMul, DivRem)を参照してください。
非プリミティブ型とオーバーフローのチェック
同じ整数型でも、decimal
の演算ではchecked
/unchecked
の指定に関わらずオーバーフローのチェックが行われる点に注意してください。 これは、int
やlong
とは異なりdecimal
はプリミティブ型ではないことが理由です。
using System;
class Sample {
static void Main()
{
decimal a = decimal.MaxValue;
decimal b = 2;
// オーバーフローのチェックを抑止したい (実際には抑止されずOverflowExceptionがスローされる)
decimal c = unchecked(a * b);
Console.WriteLine("{0} * {1} = {2}", a, b, c);
}
}
D:\>csc sample.cs && sample.exe ハンドルされていない例外: System.OverflowException: Decimal 型の値が大きすぎるか、または小さすぎます。 場所 System.Decimal.FCallMultiply(Decimal& d1, Decimal& d2) 場所 Sample.Main()
型の分類、プリミティブ型かどうかについては型の種類・サイズ・精度・値域 §.基本的なデータ型と対応する各言語の型を参照してください。
Visual Basicでのオーバーフローのチェック
VBではC#のchecked
/unchecked
ステートメントに相当するものは用意されておらず、オーバーフローのチェックをコード上・ブロックレベルで制御することができません。
ただ、コンパイルオプション/removeintchecksが用意されているので、オーバーフロー時の扱いを指定することはできます。 デフォルトでは/removeintchecks-
、つまりオーバーフローチェックの抑止がオフとなっていて、オーバーフローのチェックが行われます。 /removeintchecks+
を指定することでオーバーフローチェックの抑止がオンとなります。
Imports System
Class Sample
Shared Sub Main()
Dim a As Integer = Integer.MaxValue
Dim b As Integer = 2
' ここでオーバーフローが起こる
' オプション/removeintchecks+を付けてコンパイルする(オーバーフローチェックの抑止を有効にする)と
' 例外OverflowExceptionをスローしなくなる
Dim c As Integer = a * b
Console.WriteLine("{0} * {1} = {2}", a, b, c)
End Sub
End Class
D:\>vbc /removeintchecks+ sample.vb && sample.exe 2147483647 * 2 = -2
プロジェクトファイルでこのオプションを設定する場合は、RemoveIntegerChecksプロパティで設定します。