2012-01-21 26 views
22

Trong khi duyệt System.Zip (Delphi XE2) để xem làm thế nào nó hoạt động, tôi thấy chức năng này:`at ReturnAddress` có nghĩa là gì trong Delphi?

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

Đó là một phần at ReturnAddress rằng loại câu đố tôi.

Tôi không biết rằng at là từ khóa hợp lệ (công cụ đánh dấu cú pháp dường như không nhận ra được).

Theo IDE, nó được khai báo là System.ReturnAddress, nhưng tôi chỉ có thể tìm thấy nó được khai báo dưới dạng nhãn ở đâu đó trong mã (asm) của procedure _HandleAnyException;. Đơn vị hệ thống có đầy đủ các tham chiếu đến nó.

Vì vậy, những gì tôi muốn biết đây là:

  1. ReturnAddress là gì?
  2. Chính xác thì Raise Exception.Create ... at ReturnAddress làm gì?

Điểm thưởng nếu bạn có thể đưa ra ví dụ thực tế về nơi đây sẽ là cấu trúc hữu ích hoặc nếu bạn có thể khuyên bạn không nên sử dụng nó.

Trả lời

20

ReturnAddress là địa chỉ mà VerifyWrite sẽ trả lại khi hoàn tất.

Raise Exception.Create... at ReturnAddress có nghĩa là khi hộp thoại ngoại lệ được hiển thị, nó sẽ cho biết địa chỉ của ngoại lệ là tại ReturnAddress. Nói cách khác, thông báo ngoại lệ sẽ đọc Exception <whatever> raised at <ReturnAddress>: <Exception Message>.

Đây là một trích đoạn từ tệp trợ giúp cho Delphi 7. Nó gần giống như the online version.

Để tăng đối tượng ngoại lệ, hãy sử dụng trường hợp ngoại lệ lớp học với tuyên bố tăng. Ví dụ,

raise EMathError.Create; 

Nói chung, hình thức một tuyên bố tăng lương là

raise object at address 

nơi đối tượng và tại địa chỉ đều không bắt buộc; xem Cải thiện ngoại lệ. Khi một địa chỉ được chỉ định, nó có thể là bất kỳ biểu thức nào đánh giá thành một kiểu con trỏ , nhưng thường là một con trỏ đến một thủ tục hoặc hàm. Ví dụ:

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

Sử dụng tùy chọn này để nâng cao ngoại lệ từ một điểm trước đó trong ngăn xếp so với cái nơi mà các lỗi thực sự xảy ra.

Lưu ý câu cuối cùng nói riêng. Nó khá cụ thể về việc sử dụng at <address>.

+0

@ain: Cảm ơn bạn đã hỗ trợ định dạng. Không có nghĩa là xóa sự thật bạn đã chỉnh sửa - chỉ muốn nhấn mạnh câu cuối cùng của văn bản được trích dẫn. :) –

+4

Và việc sử dụng thế giới thực cho cấu trúc này nói chung là nếu bạn sử dụng một hàm trợ giúp * để tăng ngoại lệ. Trong VCL, ví dụ, có 'TList.Error', trong đó tất cả các lỗi liên quan đến' TList' đến từ đó. Biết một ngoại lệ được nâng lên trong hàm đó không hữu ích cho việc gỡ lỗi, do đó, nó sử dụng cú pháp 'at' để đặt lại địa chỉ ngoại lệ trong hàm gọi là' Lỗi', vì vậy khi bạn tìm địa chỉ trong tệp bản đồ của mình, bạn có một ý tưởng tốt hơn là thủ phạm. (Và tại sao lại sử dụng một helper? Đối với một, nó giữ codegen của người gọi đơn giản hơn.) –

+1

@RobKennedy: Sẽ không phải là ngăn xếp cuộc gọi tiết lộ cùng một thông tin? – afrazier

8

ReturnAddr không phải là một câu đố với các phiên bản Delphi trước đó.Hãy xem xét thử nghiệm tiếp theo (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; 

nếu bạn bấm Button3 dưới debugger và nhấn 'Break' trong ngoại lệ MessageBox, debugger dừng lại ở

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

nếu bạn bấm Button4, debugger dừng lại ở

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

Như bạn có thể thấy RaiseTest1 sửa đổi khung ngăn xếp ngoại lệ mặc định và thực hiện gỡ lỗi đơn giản hơn vì mục đích duy nhất của quy trình RaiseTest1 (2) là tăng eption.

Tôi đoán điều gì đó đã thay đổi trong XE2 để cú pháp ReturnAddr được đơn giản hóa.

+0

Tôi không hiểu cú pháp bạn nghĩ thay đổi. –

+1

@RobKennedy Tôi nghĩ anh ta có nghĩa là từ 'ReturnAddr' thành' ReturnAddress', nhưng tôi không thể tìm thấy bất kỳ tài liệu nào về điều này. Nhưng có vẻ như 'ReturnAddr' là tên của các hàm lồng nhau trong các đơn vị hệ thống (xem [bug] này (http://qc.embarcadero.com/wc/qcmain.aspx?d=71294)). – ventiseis