![]() |
Delphi-Version: 10.3 Rio
Problem mit Record-Parametern an MethodenPointer bzw. FunktionsPointer
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo Community,
ich stehe auf dem Schlauch und bräuchte mal wieder Eure Hilfe: Es geht um den Aufruf von Methoden und Funktionen über MethodenPointer und FunktionsPointer, wobei die Pointer einen Record als Parameter mitbekommen. Hierbei habe ich 3 verschiedene Varianten: 1: MethodenPointer direkt verwenden 2: Funktion wird über den FunktionsPointer aufgerufen 3: Funktion wird über den MethodenPointer aufgerufen Um die Ergebnisse auseinanderzuhalten, machen die Routinen Folgendes: – Methode: Bildet Eingabe hoch 3 – Funktion: Gibt das Quadrat der Eingabe aus Alle drei Fälle liefern zwar das korrekte Ergebnis, allerdings ist im Fall 3 innerhalb der Funktion der Inhalt des Parameter-Records ein Zufallswert, trotzdem kommt das korrekte Resultat heraus. Das verwirrt mich etwas.
Code:
Im Anhang habe ich ein einfaches Konsolenprogramm als Demo dazu.
Di Ergebnisse:
1: Methode wird direkt aufgerufen: MyMethode wurde aufgerufen! Rec.X[0] = 2.00000000000000E+0000 Rec.X[1] = 3.00000000000000E+0000 Y = X^3 = 8 + 27 -----> korrekt! 2: Funktion wird über den FunktionsPointer aufgerufen: MyFunktion wurde aufgerufen! Rec.X[0] = 2.00000000000000E+0000 Rec.X[1] = 3.00000000000000E+0000 Y = X^2 = 4 + 9 -----> korrekt! 3: Funktion wird über den MethodenPointer aufgerufen: MyFunktion wurde aufgerufen! Rec.X[0] = 2.13089722546296E-0317 -----> FALSCHER Parameter-Inhalt Rec.X[1] = 4.24412110025147E-0314 -----> FALSCHER Parameter-Inhalt Y = X^2 = 4 + 9 -----> trotzdem korrekt! ??? Vielleicht kann mir jemand auf die Sprünge helfen, denn anscheinend sehe ich vor lauter Bäumen den Wald nicht mehr… Danke für Eure Hilfe im Voraus! Gruß, Andreas |
AW: Problem mit Record-Parametern an MethodenPointer bzw. FunktionsPointer
Irgendwer (du) quetscht grob fahrlässig einen Funktions-Zeiger in eine Methoden-Zeiger-Variable,
wobei natürlich die Signatur überhaupt nicht kompatibel sind. Wenn sich jetzt jemand wundert, dass die übergebenen Parameter nicht stimmen, dann ist er selbst Schuld, weil er den impliziten (unsichtbaren) ersten Parameter "Self" ignoriert hat.
Delphi-Quellcode:
Function MyBösartigeFalscheMethodenFunktion(Self: TObject; CONST Rec: DoubleDouble): DoubleDouble;
Und nun rate mal, wie TMethod.Data in die Funktion Methode rein kommt. Zitat:
da Anzeige-Werte <> Rückgabe-Werte. :roll: Zitat:
|
AW: Problem mit Record-Parametern an MethodenPointer bzw. FunktionsPointer
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo Himitsu,
danke für Deine Anregungen und Hilfe. Ich möchte mein Problem etwas verdeutlichen: In Jahrzehnte-langer Arbeit habe ich eine große Menge an mathematischen Funktionen und Prozeduren zur Lösung verschiedenster Probleme erstellt. Meine Bibliothek liegt in proceduraler Form vor, also ohne Klassen und Objekte. Die unterschiedlichen Aufgaben (hier vereinfacht durch „MyFunktion“) übergebe ich an die Routinen mittels ProzedurPointer, daher haben all die Routinen zum Empfangen der konkretisierten Aufgabe entsprechende Pointer. Zuerst hatte ich einfache ProzedurPointer / FunktionsPointer verwendet. Da ich in den konkreten Anwendungen jedoch auch eigene Klassen und Objekte benutze, habe ich vor gut 15 Jahren alle ProzedurPointer in MethodenPointer geändert. Dann konnte allerdings ich die Bibliotheks-Routinen von einfachen Prozeduren/Funktionen nicht mehr aufrufen. Zum Glück fand ich in ![]() Seit kurzem versuche ich einige meiner bisherigen Berechnungen(Genauigkeit = Extended bzw. Multipräzisions-Arithmetik) auf den DatenType DoubleDouble bzw. QuadDouble der Neslib.MultiPrecision-Bibliothek: ![]() DoubleDouble entspricht formal obigem Record. Und hierbei tritt das neue Problem auf, dass der Record DoubleDouble – im Gegensatz zum einfachen Extended oder Double – nicht mehr als Argument an in FunktionsPointer gecastete MethodenPointer übergeben wird. Es wird zwar die richtige Funktion aufgerufen, aber der Inhalt des Records ist zufällig, als hätte der Compiler eine neue Variable auf dem Stack abgelegt und „vergessen“, den Inhalt des Parameter-Records reinzukopieren. Auch eine Änderung des Parameters von CONST in VAR, oder ohne beides, bringt nichts. Du hast recht, das frühere Ergebnis war nicht korrekt, obwohl ich die Löschroutine ClearRec(..) genau aus diesem Grund eingebaut hatte, um nicht korrekte Ergebnisse der Vorrunde ungewollt zu verschleppen und als korrekt zu übernehmen. Nach Beheben einiger Fehlern von mir & Hinzufügen eines Pointers in der Klasse habe ich eine erweiterte Demo mit 4 Möglichkeiten gemacht, wobei ich die ersten beiden funktionierenden Fälle auskommentiert habe. Leider wird immer noch ein Record mit Zufallsinhalt an die aufgerufene Funktion übergeben. Was mache ich falsch? Und vor allem, wie wäre es richtig? Dank & Gruß, Andreas |
AW: Problem mit Record-Parametern an MethodenPointer bzw. FunktionsPointer
Es ist zu warm um groß Erklärung zu suchen und aufzuschreiben, aber ich habe hier einen Workaround für dich (Ausschnitt auf das Wesentliche zum Kopieren):
Delphi-Quellcode:
Function MyFunktion(CONST Rec: DoubleDouble): DoubleDouble;
// Hoch 2: --> X*X; Begin WriteLn('MyFunktion wurde aufgerufen!'); WriteLn('Rec.X[0] = ', Rec.X[0]); WriteLn('Rec.X[1] = ', Rec.X[1]); ClearRec(Result); Result.X[0]:= Rec.X[0]*Rec.X[0]; Result.X[1]:= Rec.X[1]*Rec.X[1]; End;{MyFunktion} {--------------} function MyFunktionEx(Self: Pointer; const Rec: DoubleDouble): DoubleDouble; Begin WriteLn('MyFunktionEx wurde aufgerufen!'); Result := MyFunktion(Rec); End; VAR A : TTestObject; MPtr : Tf_x_Methode; // MethodenPointer FuPtr: Tf_x_Function; // FunktionsPointer X, Y: DoubleDouble; Begin Try A:= TTestObject.Create; Try X.X[0]:= 2; X.X[1]:= 3; ClearRec(Y); WriteLn; // 3: EXTERNEN MethodenPointer als FunktionsPointer verwenden: WriteLn('3: Funktion wird über den EXTERNEN MethodenPointer aufgerufen:'); // A:= TTestObject.Create; ist nötig!!!! // EXTERNEN MethodenPointer in FunktionsPointer umwandeln: TMethod(MPtr).Code:= @MyFunktionEx; // wird vom Compiler NICHT gesetzt, weil EXTERNER MethodenPointer! TMethod(MPtr).Data:= @A; // selber setzen ClearRec(Y); Y:= MPtr(X); // Ein Record mit Zufallsinhalt wird an die Funktion übergeben! Print('Y = X^2 = ', Y); WriteLn; WriteLn; WriteLn('4: Funktion wird über den MethodenPointer des Objektes aufgerufen:'); TMethod(A.Ptr).Code:= @MyFunktionEx; // TMethod(Ptr).Data wird vom Compiler NICHT automatisch gesetzt! TMethod(A.Ptr).Data:= @A; // Sonst ist Record X ist in der Funktion gar NICHT existent! ClearRec(Y); Y:= A.Ptr(X); // Ein Record mit Zufallsinhalt wird an die Funktion übergeben! Print('Y = X^2 = ', Y);
Code:
3: Funktion wird über den EXTERNEN MethodenPointer aufgerufen:
MyFunktionEx wurde aufgerufen! MyFunktion wurde aufgerufen! Rec.X[0] = 2.00000000000000E+0000 Rec.X[1] = 3.00000000000000E+0000 Y = X^2 = 4 + 9 4: Funktion wird über den MethodenPointer des Objektes aufgerufen: MyFunktionEx wurde aufgerufen! MyFunktion wurde aufgerufen! Rec.X[0] = 2.00000000000000E+0000 Rec.X[1] = 3.00000000000000E+0000 Y = X^2 = 4 + 9 |
AW: Problem mit Record-Parametern an MethodenPointer bzw. FunktionsPointer
Vielen Dank, TiGü: Es funktioniert!
Nach Deiner Idee konnte ich den Aufruf sogar noch weiter vereinfachen, indem ich direkt MyFunktion(..) um den Eintrag
Delphi-Quellcode:
erweitert habe:
Self: Pointer;
Delphi-Quellcode:
Zwar kapiere ich immer noch nicht, warum der mit einfachen Datentypen gängige Weg mit Records nur mit Self funktioniert, aber im Moment ist für mich nur wichtig, daß es klappt. Ich muß ja nicht alles verstehen...
Function MyFunktion(Self: Pointer; CONST Rec: DoubleDouble): DoubleDouble;
. . . Danke Dir noch einmal: Du hast mir sehr geholfen! :thumb: :angel: Gruß, Andreas PS: So funktionieren alle vier Varianten! |
AW: Problem mit Record-Parametern an MethodenPointer bzw. FunktionsPointer
Sorry, ich war wohl etwas voreilig und muß meine letzte pauschale Aussage etwas relativieren: :oops: Variante 2, also die direkte Verwendung des FunktionsPointers funktioniert doch NICHT (mehr).
Abhilfe: Stets MethodenPointer benutzen! Ein auf FunktionsPointer gecasteter externer MethodenPointer funktioniert nämlich immer korrekt. Vorteil: Die Erzeugung des Objectes durch
Delphi-Quellcode:
ist nicht nötig.
TTestObject.Create;
Andreas |
AW: Problem mit Record-Parametern an MethodenPointer bzw. FunktionsPointer
Oder die Generics -> reference to
Alle "offiziellen" Möglichkeiten, ohne an der automatischen Typbehandlung rumzupfuschen:
Delphi-Quellcode:
type
TTest = class function A(): Boolean; function B(): Boolean; virtual; // bzw. overload oder auch dynamic class function C(): Boolean; class function D(): Boolean; virtual; // bzw. overload oder auch dynamic class function E(): Boolean; static; end; function F(): Boolean; { E entspricht F A = C (nur eben TClass statt TObject, beim Self) A und C auch mit Data/Self=NIL möglich } var X: function(): Boolean; // E oder F Y: function(): Boolean of object; // A, B, C oder D Z: reference to function(): Boolean; // alles, inkl. anonymer Methoden (nicht direkt als VAR ... muß einen TYPE haben) O: TTest; L: class of TTest; O := TTest.Create; X := TTest.E; // oder L.E oder O.E inkl. O=nil X := F; Y := O.A; // auch O=nil Y := O.B; Y := TTest.C; // oder L.C oder O.C inkl. L=nil Y := TTest.D; // oder L.D oder O.D Z := egal was |
AW: Problem mit Record-Parametern an MethodenPointer bzw. FunktionsPointer
Danke, Himitsu!
Ich werde versuchen, Deinen recht konzentrierten Code zu verstehen. Leider habe ich noch etliche Lücken bezüglich Generics, anonymer Methoden etc. :oops: Gruß, Andreas |
AW: Problem mit Record-Parametern an MethodenPointer bzw. FunktionsPointer
Bei "reference to procedure" werden intern quasi die Generics verwendet ... du selbst hast hier nichts damit zu tun ... macht alles der Compiler von selbst.
|
AW: Problem mit Record-Parametern an MethodenPointer bzw. FunktionsPointer
Ja genau. Einfach "reference to" dazu und Hirn abschalten :-)
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 23:09 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz