2013年6月2日

キャストの比較 #2 オーバーフロー

キャストまたは算術演算(+、-、*、/) でオーバーフローが発生した際の挙動は、2種類ある。
  1. OverflowException をスロー
  2. 結果の最上位ビットを破棄

どちらの挙動にするかは、プロジェクト単位の設定、または C# なら checkedunchecked 構文が使える。
逆に言えば、VB.NET はプロジェクト単位でしか、オーバーフロー時の挙動を制御できない。
また、プロジェクト単位の設定オプションは下表になるが、注意すべきは C# と VB.NET で設定するチェックボックスの意味が逆という点。
デフォルト設定は両方チェック OFF、つまり、C# はオーバーフロー時の例外を発生させない、VB.NET は発生させる、と逆の挙動になっている。
オーバーフロー時の挙動設定オプション (Visual Studio 2010) デフォルト設定
C#.NET プロジェクトのプロパティ → [ビルド]タブ → [詳細設定]ボタン
→ [演算のオーバーフローおよびアンダーフローのチェック]チェックボックス
チェック OFF
VB.NET プロジェクトのプロパティ → [コンパイル]タブ → [詳細設定コンパイル オプション]ボタン
→ [演算のオーバーフローのチェックを解除]チェックボックス
チェック OFF

定数値のオーバーフロー

定数値のキャスト・算術演算でオーバーフローが発生する場合、コンパイルの挙動が C# と VB.NET で異なる。
オーバーフローチェック無し オーバーフローチェック有り
C#.NET チェック有無に関わらず、コンパイルエラー。
unchecked 構文を使うとコンパイルできる。
VB.NET キャストはコンパイル可能。
算術演算はコンパイルエラー。
キャスト・算術演算ともにコンパイルエラー。
  • C# の例

//定数値のキャストでオーバーフロー → 要 unchecked
int val1 = (int)2147483648L;
//定数値の算術演算でオーバーフロー → 要 unchecked
int val2 = 2147483647 + 1;
  • VB.NET の例

'定数値のキャストでオーバーフロー → オーバーフローチェック解除でコンパイル可
Dim val1 As Integer = CType(2147483648L, Integer);
'定数値の算術演算でオーバーフロー → 常にコンパイル不可
Dim val2 As Integer = 2147483647 + 1;

MSIL比較

オーバーフローチェック有無による MSIL の相違点は、「.ovf」の有無。
例:数値型から int にキャストする場合
オーバーフローチェック無し conv.i4
オーバーフローチェック有り conv.ovf.i4

検証環境

Windows 7 64bit/Visual Studio 2010 SP1/.NET 4.0

0 件のコメント:

コメントを投稿