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を呼ぶ場合に、この振る舞いは深刻な問題を引き起こします。
|