私は正しいと思われるDelphiコードに対して予期しないアクセス違反がありますが、誤ってコンパイルされているようです。私はそれを減らすことができます匿名プロシージャとネストされたプロシージャを組み合わせたときのコードが間違っています
procedure Run(Proc: TProc);
begin
Proc;
end;
procedure Test;
begin
Run(
procedure
var
S: PChar;
procedure Nested;
begin
Run(
procedure
begin
end);
S := 'Hello, world!';
end;
begin
Run(
procedure
begin
S := 'Hello';
end);
Nested;
ShowMessage(S);
end);
end;
私には、S := 'Hello, world!'
が間違った場所に格納されています。そのため、アクセス違反が発生するか、ShowMessage(S)
が "Hello"を示します(また、匿名プロシージャの実装に使用されるオブジェクトを解放するときにアクセス違反が発生することもあります)。
私はすべてのアップデートがインストールされているDelphi XEを使用しています。
これがどこに問題を引き起こすかをどのように知ることができますか?私は匿名の手続きを避けるためにコードを書き直す方法を知っていますが、間違ったコードにつながる状況を正確に把握することができないので、どこを避けるべきかわかりません。
これがDelphiのそれ以降のバージョンで修正されているのは興味深いですが、興味深いだけではありません。この時点でアップグレードはオプションではありません。
QCの最新のレポートでは、同様の#91876が見つかりましたが、それはDelphi XEで解決されています。
更新:AlexSCのコメントに基づいて
、若干の変更で:
...
procedure Nested;
begin
Run(
procedure
begin
S := S;
end);
S := 'Hello, world!';
end;
...
が作業を行います。正しいバージョンが失敗したプログラムで生成されたコードを見ていない
ScratchForm.pas.45: S := 'Hello, world!';
004BD981 B8B0D94B00 mov eax,$004bd9b0
004BD986 8B5508 mov edx,[ebp+$08]
004BD989 8B52FC mov edx,[edx-$04]
004BD98C 89420C mov [edx+$0c],eax
ある一方
失敗プログラムで
S := 'Hello, world!';
用に生成されたマシンコードは
ScratchForm.pas.44: S := 'Hello, world!';
004BD971 B89CD94B00 mov eax,$004bd99c
004BD976 894524 mov [ebp+$24],eax
ありますS
がコンパイラ生成クラスに移動されましたはです。ネストされたメソッドの外側ローカル変数へのアクセス方法ローカル変数のアクセス方法
私のテストでは、「[DCC警告] Unit1.pas(45):W1036変数 '$ frame'が初期化されていない可能性があります。私は$フレーム変数を宣言していないので、匿名メソッドを実装するインターフェイスを宣言するときに、コンパイラによって生成されたと仮定します。この警告は、コンパイラによってすべてが正しく行われたわけではないことを示しているため、バグのようです。文字列としてS変数を宣言するようにコードを変更すると、問題が早期に表示されます。デバッグは、S変数が生成されたコードによって適切に処理されなかったことを示唆しています。 – AlexSC
@AlexSC "初期化されていない可能性があります"という検出は悪いことですが、実際の問題を指摘せず、生成されたコードには影響しない誤検出が数多くあるため、無視しても安全です。また、正しく動作するより単純なコードで警告( '$ frame'コンパイラ生成変数を含む)を得ることもできます。 – hvd
XE2でコンパイルしてもうまく動作します –