- お知らせ -
  • 当wikiのプログラムコードの表示を直してみました(ついでに長い行があると全体が下にぶっ飛ぶのも修正)。不具合があればBBSまでご連絡下さい。

{$RANGECHECKS}とは? Edit

実行時の範囲チェックを有効/無効にするコンパイラオプションです。
以下、Delphi6のヘルプより。

説明
$R 指令は,範囲チェックコードの生成を使用可能または使用不可にします。
{$R+} 状態にすると,すべての配列および文字列の添字式が定義された範囲内に
あるかどうかが検査されます。また,スカラー型および部分範囲型変数へのすべての
代入が範囲内にあるかどうかも検査されます。範囲チェックに失敗すると,
ERangeError 例外が生じます
(例外ハンドラが使用できない場合はプログラムが終了します)。
範囲チェックを有効にすると,プログラムの速度が低下しサイズも大きくなります。
したがって,{$R+} はデバッグ用にのみ使用してください。

メモ:長い文字列は,範囲チェックされません。

デバッグ時のみ使え、とのことですが、
使い方によっては、相当エラーチェックを省けるのではないか、と。

どんなときに働くのか? Edit

期待通りに動いてくれなければ、信用できないので、
どんなときに働くのか、調べてみます。

静的配列 Edit

結果 Edit

チェックしてくれます。

コード例 Edit

{$RANGECHECKS ON}
procedure Test;
var
  TestStaticArray: array [0..2] of Integer;
begin
  // Random(0) は、コンパイル時に検出されるエラーを回避するため
  TestStaticArray[Length(TestStaticArray) + Random(0)] := 123;
end;
{$RANGECHECKS OFF}

動的配列 Edit

結果 Edit

問題なくチェックしてくれます。

コード例 Edit

uses Types;
 :
{$RANGECHECKS ON}
procedure Test;
var
  TestDynamicArray: TIntegerDynArray;
begin
  SetLength(TestDynamicArray, 10);
  TestDynamicArray[Length(TestDynamicArray)] := 1234;
end;
{$RANGECHECKS OFF}

列挙型 Edit

結果 Edit

キャストして範囲外の値を代入した場合は、チェックしてくれません。ガーン。

やはり、キャストは危険……。

コード例 Edit

{$RANGECHECKS ON}
procedure Test;
type TTest = (Hoge, Moge, Mage);
var TestEnum: TTest;
begin
  TestEnum := TTest(-1);
  Writeln(Integer(TestEnum));  // 最適化による消滅防止

  TestEnum := TTest(Integer(Mage) + 1);
  Writeln(Integer(TestEnum));  // 最適化による消滅防止
end;
{$RANGECHECKS OFF}

このコード例では、例外が起きません。

回避法 Edit

明示的に範囲チェックするほかないのだろうか。

TestEnum := TTest(-1);
if not (TestEnum in [Low(TTest)..High(TTest)]) then
  raise SysUtils.ERangeError.Create(SysConst.SRangeError);

上の例では、列挙要素の値が0〜255の時しかチェックできないので、もしくは、

TestEnum := TTest(-1);
if (TestEnum < Low(TTest)) and (High(TTest) < TestEnum) then
  raise SysUtils.ERangeError.Create(SysConst.SRangeError);

する。

in が順序型や列挙型で使えればなあ。

TestEnum := TTest(-1);
if not(TestEnum in TTest) then  // ×当然コンパイルエラーだけど
  raise SysUtils.ERangeError.Create(SysConst.SRangeError);

あと、as が使うと代入時に範囲チェックしてくれるとかー。

TestEnum := -1 as TTest;  // ×コンパイルエラーだけどね

結論 Edit

少なくとも列挙型とそれへのキャストを多用する自分は、安心して使えない。
が、しかし、配列のアクセス等の使用には問題ないので部分的には使える、かな。

実際、列挙型へのキャストなんて、外部ファイルからの読み込み時ぐらいだし。
例えば記述力が低いスクリプトからデータを読む場合、
文字列で列挙要素を記述することも(後でTypInfo.GetEnumValueで変換)できるが、
やむを得ず、整数でしか列挙要素をあらわせない場合があったりする。


  • array of IntegerをTIntegerDynArrayに修正 -- TOBY 2008-10-21 (Tue) 16:23:32


Front page   Edit Freeze Diff Backup Upload Copy Rename Reload   New Pages Search Recent changes   Help   RSS of recent changes
Last-modified: 2008-10-21 Tue 16:23:38 JST (3261d)