2012-01-21 6 views
22

Mientras navega System.Zip (Delphi XE2) para ver cómo funciona, me encontré con esta función:¿Qué significa `en ReturnAddress` en Delphi?

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

Es la parte at ReturnAddress ese tipo de me intriga.

No sabía que at era una palabra clave válida (el marcador de sintaxis tampoco parece reconocerlo).

Según el IDE, se declara como System.ReturnAddress, pero solo puedo encontrarlo declarado como una etiqueta en algún lugar del código (asm) de procedure _HandleAnyException;. Sin embargo, la unidad del sistema está llena de referencias.

Así que lo que me gustaría saber es esto:

  1. ¿Cuál es ReturnAddress?
  2. ¿Qué hace exactamente Raise Exception.Create ... at ReturnAddress do?

Bonuspoints si puede dar un ejemplo del mundo real de dónde podría ser una construcción útil, o si puede aconsejar no usarlo.

Respuesta

20

ReturnAddress es la dirección a la que VerifyWrite habría regresado cuando haya terminado.

Raise Exception.Create... at ReturnAddress significa que cuando se muestra el cuadro de diálogo de excepción, indicará que la dirección de la excepción está en ReturnAddress. En otras palabras, el mensaje de excepción leería Exception <whatever> raised at <ReturnAddress>: <Exception Message>.

Aquí hay un extracto del archivo de ayuda para Delphi 7. Es casi lo mismo que the online version.

Para generar un objeto de excepción, use una instancia de la clase de excepción con una instrucción raise. Por ejemplo,

raise EMathError.Create; 

En general, la forma de una declaración plantear es

raise object at address 

donde objeto y en la dirección son opcionales; ver Reanudar excepciones. Cuando se especifica una dirección, puede ser cualquier expresión que evalúe a un tipo de puntero , pero generalmente es un puntero a un procedimiento o función. Por ejemplo:

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

Utilice esta opción para elevar la excepción desde un punto anteriormente en la pila de aquél en realidad se produjo el error.

Tenga en cuenta la última frase en particular. Es muy específico sobre el uso de at <address>.

+0

@ain: Gracias por la asistencia de formateo. No quiso eliminar el hecho de que editó; solo quería recalcar la última frase del texto citado. :) –

+4

Y el uso del mundo real para este constructo generalmente es si usa una función * helper * para generar una excepción. En el VCL, por ejemplo, está 'TList.Error', de donde provienen todos los errores' TList'. Saber que se generó una excepción en esa función no es útil para la depuración, por lo que utiliza la sintaxis 'at' para devolver la dirección de excepción a la función que llamó' Error', por lo que cuando busca la dirección en su archivo de mapa, tienes una mejor idea de quién fue el culpable. (¿Y por qué usar un ayudante? Por un lado, mantiene el codegen de los llamadores más simple.) –

+1

@RobKennedy: ¿No mostraría la pila de llamadas la misma información? – afrazier

8

ReturnAddr no era un rompecabezas con versiones anteriores de Delphi.Considere la siguiente prueba (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; 

si pulsa Button3 bajo el depurador y presione 'pausa' del cuadro de mensaje de excepción, depurador se detiene en

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

si pulsa Button4, depurador se detiene en

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

Como puede ver, RaiseTest1 modifica el marco predeterminado de la pila de excepción y hace que la depuración sea un poco más directa ya que el único propósito de los procedimientos de RaiseTest1 (2) es generar un exc. eption

Supongo que algo cambió en XE2, por lo que la sintaxis ReturnAddr se simplifica.

+0

No entiendo qué sintaxis crees que ha cambiado. –

+1

@RobKennedy Creo que quiere decir desde 'ReturnAddr' a' ReturnAddress', pero no pude encontrar ninguna documentación para esto. Pero parece que 'ReturnAddr' era el nombre de las funciones anidadas en las unidades del sistema (vea este [error] (http://qc.embarcadero.com/wc/qcmain.aspx?d=71294)). – ventiseis