The Delphi Bug List

Entry No.
567
コンパイラ - コード生成
型無しvarパラメータに動的配列を渡すと、予期せぬ結果を引き起こす
1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02 4.03 5.0 5.01 6.0 6.01 6.02 Kylix 1.0
N/A N/A N/A N/A N/A Gotcha Gotcha Gotcha Gotcha Gotcha Gotcha Gotcha Gotcha Gotcha Unknown
解説
Reported by Michael Winter
次のプロシージャは、与えられた型無し引数の先頭4バイトを整数と解釈し、それを16進数で表示します。
procedure Verify(var X);
begin
  ShowMessage(IntToHex(Integer(X), 8));
end;
次のコードでVerifyを呼び出すと、03020100という期待通りの出力になります。
var StatArray: Array[0..3] of Byte;
...
  for i:=0 to 3 do StatArray[i]:=i;
  Verify(StatArray);
代わりに動的配列を使用すると、驚いたことに上と同じ値ではなく、配列のアドレスが表示されます。
var DynaArray: Array of Byte;
...
  SetLength(DynaArray, 4);
  for i:=0 to 3 do DynaArray[i]:=i;
  Verify(DynaArray);
この振る舞いは文書化されていないので、混乱の元(gotcha)です。

原因
静的配列は、配列の先頭アドレスからデータを保持します(つまり@StatArrayと@StatArray[0]は等しくなります)。動的配列の場合、コンパイラは動的配列を維持するために追加のデータを作成し、実際のデータはヒープに保存されます(つまり@DynArrayと@DynArray[0]は等しくなりません)。残念ながらコンパイラは、varパラメータへの静的配列と動的配列とに、同じコードを生成してしまいます。

注意:
動的配列にゼロを設定するためにFillCharを呼ぶ場合や、動的配列の読み書きのためにBlockRead/BlockWriteを呼ぶ場合に、この振る舞いは深刻な問題を引き起こします。

解決策 / 回避方法
代わりに Verify(DynaArray[0]) を使用します。
Latest update of this entry: 1999-10-02
本家 The Delphi Bug List のエントリーはこちら
The Delphi Bug List 日本語訳 へ