2012-01-21 7 views
22

、私はこの機能を見つけました:Delphiでは `at ReturnAddress`とはどういう意味ですか?それがどのように動作するか確認するためにSystem.Zip(デルファイXE2)を閲覧している間

procedure VerifyWrite(Stream: TStream; var Buffer; Count: Integer); 
begin 
    if Stream.Write(Buffer, Count) <> Count then 
    raise EZipException.CreateRes(@SZipErrorWrite) at ReturnAddress; 
end; 

それは一種の私を困惑at ReturnAddress部分です。

atが有効なキーワードであることがわかりませんでした(ハイライト表示でも認識されないようです)。

IDEによれば、それはSystem.ReturnAddressと宣言されていますが、(asm)コードprocedure _HandleAnyException;のどこかでラベルとして宣言されています。システム・ユニットには参照がいっぱいです。

それでは、私が知りたいのはこれです:ReturnAddressある

  1. 何?
  2. 正確にRaise Exception.Create ... at ReturnAddressとは何ですか?

実用的な例であればどこに役立つのか、それが役に立つかどうかをアドバイスできれば、ボーナスポイントが得られます。

答えて

20

ReturnAddressは、終了時にVerifyWriteが返されるアドレスです。

Raise Exception.Create... at ReturnAddressは、例外ダイアログが表示されたときに、例外のアドレスがReturnAddressであることを示します。つまり、例外メッセージはException <whatever> raised at <ReturnAddress>: <Exception Message>となります。

デルファイ7のヘルプファイルの抜粋です。the online versionとほぼ同じです。

例外オブジェクトを発生させるには、raise文で例外 クラスのインスタンスを使用します。例えば、一般的に

raise EMathError.Create; 

は、raise文の形式は、オブジェクトとアドレスには、両方のオプションである

raise object at address 

あります。 例外を再発生するを参照してください。アドレスが指定されている場合、 は、ポインタ の型に評価される任意の式ですが、通常はプロシージャまたは関数へのポインタです。たとえば :

raise Exception.Create('Missing parameter') at @MyFunction; 

エラーが実際に発生し1よりスタック内でより早い時点 から例外を発生させるために、このオプションを使用します。

特に最後の文に注意してください。 at <address>の使用についてはかなり具体的です。

+0

@ain:フォーマット支援に感謝します。引用したテキストの最後の文章を強調したいだけで、編集した事実を削除することを意味しませんでした。 :) –

+4

そして、実際には、例外を発生させるために*ヘルパ関数*を使用すると、このコンストラクトの実際の使用が一般的です。たとえば、VCLでは、 'TList.Error'があります。ここでは、' TList'関連のエラーがすべて発生します。その関数で例外が発生したことがデバッグには役に立たないことを知っているので、 'at'構文を使用して例外アドレスを' Error'という関数に戻します。そのため、マップファイルのアドレスを調べるとき、犯人が誰であったか、あなたは良い考えを持っています。 (なぜヘルパーを使用するのですか?1つは、呼び出し元のコードジェネをよりシンプルに保ちます) –

+1

@RobKennedy:コールスタックが同じ情報を表示しないでしょうか? – afrazier

8

ReturnAddr以前のDelphiバージョンのパズルではありませんでした。次のテスト(デルファイXE)を考えてみましょう:

procedure RaiseTest1; 

    procedure RaiseException(ReturnAddr: Pointer); 
    begin 
    raise Exception.Create('OOPS!') at ReturnAddr; 
    end; 

asm 
     POP EAX 
     JMP RaiseException 
end; 

procedure RaiseTest2; 
begin 
    raise Exception.Create('OOPS!'); 
end; 


procedure TForm1.Button3Click(Sender: TObject); 
begin 
    RaiseTest1; 
end; 

procedure TForm1.Button4Click(Sender: TObject); 
begin 
    RaiseTest2; 
end; 

あなたはボタン4を押した場合は、例外メッセージボックスで「ブレーク」デバッガと押し下ボタン3を押すと、デバッガは

procedure TForm1.Button3Click(Sender: TObject); 
begin 
    RaiseTest1; // <-- here 
end; 

で停止し、デバッガが

で停止
procedure RaiseTest2; 
begin 
    raise Exception.Create('OOPS!'); // <-- here 
end; 

RaiseTest1は、デフォルトの例外スタックフレームを変更し、さらに簡単にデバッグすることができます。これは、RaiseTest1(2)の唯一の目的は、exc eption。

ReturnAddrシンタックスが簡略化されるように、XE2で何かが変更されたようです。

+0

変更されたと思われる構文がわかりません。 –

+1

@RobKennedy私は彼が 'ReturnAddr'から' ReturnAddress'までを意味すると思いますが、私はこれに関するドキュメントを見つけることができませんでした。しかし、 'ReturnAddr'はシステム単位でネストされた関数の名前だったようです(この[bug](http://qc.embarcadero.com/wc/qcmain.aspx?d=71294)参照)。 – ventiseis

関連する問題