Reported by Jani Järvinen; checked by Reinier Sterkenburg
サンプル:
program Project1;
{$OPTIMIZATION ON}
Uses Dialogs,SysUtils;
Var I, J: Integer;
begin
J := 123;
A: I := I+J;
B: I := J-I; { ここで警告: 変数 "I" は初期化されない場合があります }
ShowMessage(IntToStr(I));
end.
上の簡単なサンプルプログラムは、結果としてゼロを表示するべきです。A の行においてこのプログラムは、グローバル変数がゼロで初期化されるという動作に依存しています。つまり、ここでの加算は必要ではなく、代入(I := J)と同じ意味となります。次に B の行で減算を実行しているので、その結果はゼロであるべきです。しかし最適化が有効になっていると、結果はゴミ値(大抵は-5636096のような値)になります。
グローバル変数がゼロに初期化されるという事がどこに書かれているのか疑問に思うでしょう。それは言語ガイド(Delphi 2 ?)の 47 ページの第四段落に書かれています。:"グローバル変数が明示的に初期化されていない場合、その変数が占めるメモリはゼロで初期化されます。"
これは BP 7.0 以来良く知られた言語の特徴で、Delphi 4 のオンラインヘルプにも記述されています。またこれは、"データセグメントのクリア" としても知られており、全ての初期化されない変数にはゼロがセットされます。例えばポインタには nil 、string には空文字('')がセットされます。
原因:
コンパイラは変数 I をメモリではなく CPU レジスタに置くように最適化し、I のために使われるレジスタはクリアされません。アセンブルされたコードを見れば、EBX レジスタがクリアされず、ゴミ値を含んでいる事が分かるでしょう。このバグの理由は、B の行で変数 I が初期化されないかもしれない為、オプティマイザが混乱して誤ったコードを提供するかもしれないという、誤った警告であるように思えます(この警告は A の行では起こるべきでは?)。スタックやメモリに置かれた変数は、このような状況でもうまく動作しているように見えます。
|