Что означает `at ReturnAddress` в Delphi? - PullRequest
25 голосов
/ 21 января 2012

Просматривая System.Zip (Delphi 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;.Хотя системный блок полон ссылок на него.

Итак, я хотел бы знать следующее:

  1. Что такое ReturnAddress?
  2. Что именно делает Raise Exception.Create ... at ReturnAddress?

Бонусные очки, если вы можете привести пример из реальной ситуации, где это будет полезная конструкция, или если вы можетесовет против его использования.

Ответы [ 2 ]

20 голосов
/ 21 января 2012

ReturnAddress - это адрес, по которому VerifyWrite возвратился бы, когда закончил.

Raise Exception.Create... at ReturnAddress означает, что при отображении диалогового окна исключения будет указан адрес исключения как ReturnAddress.Другими словами, сообщение об исключении будет иметь вид Exception <whatever> raised at <ReturnAddress>: <Exception Message>.

Вот выдержка из файла справки для Delphi 7. Она почти такая же, как онлайн-версия .

Чтобы вызвать объект исключения, используйтеЭкземпляр класса исключения с оператором повышения.Например,

raise EMathError.Create;

В общем случае форма запроса на повышение равна

raise object at address

, где объект и адрес не являются обязательными;см. Возвышение исключений.Когда указан адрес, это может быть любое выражение, которое оценивает тип указателя, но обычно это указатель на процедуру или функцию.Например:

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

Используйте эту опцию, чтобы вызвать исключение из более ранней точки в стеке, чем точка, в которой фактически произошла ошибка.

Обратите особое внимание на последнее предложение,Это довольно специфично в отношении использования at <address>.

8 голосов
/ 21 января 2012

ReturnAddr не было загадкой с предыдущими версиями Delphi.Рассмотрим следующий тест (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;

, если вы нажмете Button3 в отладчике и нажмете «Break» в окне сообщений об исключении, отладчик остановится на

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

, если вы нажмете Button4, отладчикостанавливается на

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

Как вы можете видеть, RaiseTest1 изменяет кадр стека исключений по умолчанию и делает отладку немного более простой, поскольку единственная цель процедур RaiseTest1 (2) - вызвать исключение.

Я думаю, что-то изменилось в XE2, так что синтаксис ReturnAddr упрощен.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...