Registriert seit: 23. Sep 2002
Ort: Frankfurt am Main (in der Nähe)
1.838 Beiträge
Delphi 10 Seattle Enterprise
|
Re: Handling von Fehlern, Warnungen und Hints
18. Sep 2008, 11:34
Hallo ich habe mal den Sachverhalt von Dezipaitor in einem kompilierbaren Beispiel verdeutlicht.
Vorgehensweise zum selbst Testen: - Quelltext der Unit komplett markieren und kopieren (Strg+C)
- Neue Anwendung erstellen einen TButton drauf, ein TMemo drauf.
- Den Button doppelklicken -> Quelltextfenster mit Methoden erscheint.
- Kompletten Quelltext mit Strg+A markieren und durch Strg+V mit dem aus der Zwischenablage ersetzen.
- Kopileren und debuggen.
Dei Kommentare im Code sollten alles erklären.
mfg
MaBuSE
Delphi-Quellcode:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
private
{ Private-Deklarationen }
public
{ Public-Deklarationen }
end;
var
Form1: TForm1;
// Hier werden die kompletten Funktionen definiert
// Im implementation Teil darf dann die Definition etwas abgekürzt werden
// (Z.B. darf der Rückgabetyp weggelassen werden.)
function TestIt1: Pointer;
function TestIt2: Pointer;
function TestIt3: Pointer;
function TestIt4: Pointer;
implementation
{$R *.dfm}
var
_TestIt1: Pointer;
_TestIt2: Pointer;
function TestIt1;
begin
// Der Variable _TestIt1 wird das Ergebnis zugewiesen, das hat nix mit Result
// zu tun -> Result ist undefiniert und war bei meinen Tests nicht immer nil!
_TestIt1 := @Form1;
end;
function TestIt2;
begin
// Der Variable _TestIt2 wird die Adresse der Funktion TestIt3 zugewiesen,
// das hat nix mit Result zu tun -> Result ist noch undefiniert.
_TestIt2 := @TestIt4;
// Hier wird direkt in die TestIt4 Funktion gesprungen
// -> also zu dem Result := @Form1 , danach wird nur ein RET duchgeführt.
// Damit ist in dem EAX-Register zur Rückgabe der Wert @Form1 enthalten
// und das Result wurde damit implizit gesetzt.
asm
JMP _TestIt2
end;
end;
// Hier funktioniert es nicht, da der Compiler erkennt, das TestIt4 das
// EAX-Register verändert. Deshalb baut er beim Begin ein Push EBX ein
// Das Result würde nun in EBX gespeichert und beim end; wieder in EAX
// kopiert und der ursprüngliche EBX Wert wieder hergestellt (pop ebx).
// Damit ist das Result wieder undefiniert ;-)
function TestIt3;
begin // ASM: 53 - push ebx
TestIt4; // ASM: E806000000 - call TestIt4
end; // ASM: 8BC3 - mov eax,ebx
// ASM: 5B - pop ebx
// ASM: C3 -ret
function TestIt4;
begin
Result := @Form1; // ASM: B8C80C4600 - mov eax, @Form1
end; // ASM: C3 - ret
procedure TForm1.Button1Click(Sender: TObject);
var
p: Pointer;
begin
// Anmerkung die p := nil; Zeilen werden vom Compiler alle wegoptimiert.
// Sie dienen nur der Übersichtlichkeit ;-)
p := nil;
p := TestIt1; // p ist undefiniert (kann, muß aber nicht nil sein)
Memo1.Lines.Add(' p = $'+ IntToHex(Integer(p),8));
Memo1.Lines.Add(' _TestIt1 = $'+ IntToHex(Integer(_TestIt1),8));
p := nil;
p := TestIt2; // in p steht das richtige Ergebnis
Memo1.Lines.Add(' p = $'+ IntToHex(Integer(p),8));
Memo1.Lines.Add(' _TestIt2 = $'+ IntToHex(Integer(_TestIt2),8));
p := nil;
p := TestIt3; // p ist undefiniert (kann, muß aber nicht nil sein)
Memo1.Lines.Add(' p = $'+ IntToHex(Integer(p),8));
p := nil;
p := TestIt4; // in p steht das richtige Ergebnis
Memo1.Lines.Add(' p = $'+ IntToHex(Integer(p),8));
end;
end.
(°¿°) MaBuSE - proud to be a DP member
(°¿°) MaBuSE - proud to be a "Rüsselmops" ;-)
|
|
Zitat
|