AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Object-Pascal / Delphi-Language Problem mit Record-Parametern an MethodenPointer bzw. FunktionsPointer

Problem mit Record-Parametern an MethodenPointer bzw. FunktionsPointer

Ein Thema von Andreas13 · begonnen am 19. Jun 2021 · letzter Beitrag vom 24. Jun 2021
Antwort Antwort
Seite 1 von 2  1 2   
Andreas13

Registriert seit: 14. Okt 2006
Ort: Nürnberg
709 Beiträge
 
Delphi XE5 Professional
 
#1

Problem mit Record-Parametern an MethodenPointer bzw. FunktionsPointer

  Alt 19. Jun 2021, 23:34
Delphi-Version: 10.3 Rio
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:
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! ???
Im Anhang habe ich ein einfaches Konsolenprogramm als Demo dazu.
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
Angehängte Dateien
Dateityp: zip Record_an_MethodenPointer_1.zip (1,0 KB, 6x aufgerufen)
Grüße, Andreas
Wenn man seinem Nächsten einen steilen Berg hinaufhilft, kommt man selbst dem Gipfel näher. (John C. Cornelius)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.017 Beiträge
 
Delphi 12 Athens
 
#2

AW: Problem mit Record-Parametern an MethodenPointer bzw. FunktionsPointer

  Alt 20. Jun 2021, 03:31
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.

Function MyBösartigeFalscheMethodenFunktion(Self: TObject; CONST Rec: DoubleDouble): DoubleDouble;



Und nun rate mal, wie TMethod.Data in die Funktion Methode rein kommt.





Zitat:
trotzdem korrekt! ???
Ja klar, weil muß ja korrekt sein,
da Anzeige-Werte <> Rückgabe-Werte.

Zitat:
Delphi-Quellcode:
  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}
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests

Geändert von himitsu (20. Jun 2021 um 03:38 Uhr)
  Mit Zitat antworten Zitat
Andreas13

Registriert seit: 14. Okt 2006
Ort: Nürnberg
709 Beiträge
 
Delphi XE5 Professional
 
#3

AW: Problem mit Record-Parametern an MethodenPointer bzw. FunktionsPointer

  Alt 20. Jun 2021, 12:36
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 https://www.delphi-treff.de/object-p...ethodenzeiger/ die Möglichkeit, „eine gewöhnliche Prozedur als Methode zu missbrauchen“. Und das hat bisher auch hervorragend funktioniert. Und damit kann ich mit MethodenPointern sowohl Methoden, wie auch externe Funktionen aufrufen.

Seit kurzem versuche ich einige meiner bisherigen Berechnungen(Genauigkeit = Extended bzw. Multipräzisions-Arithmetik) auf den DatenType DoubleDouble bzw. QuadDouble der Neslib.MultiPrecision-Bibliothek: https://github.com/neslib/Neslib.MultiPrecision umzustellen.
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
Angehängte Dateien
Dateityp: zip Record_an_MethodenPointer_2.zip (1,3 KB, 5x aufgerufen)
Grüße, Andreas
Wenn man seinem Nächsten einen steilen Berg hinaufhilft, kommt man selbst dem Gipfel näher. (John C. Cornelius)
  Mit Zitat antworten Zitat
TiGü

Registriert seit: 6. Apr 2011
Ort: Berlin
3.058 Beiträge
 
Delphi 10.4 Sydney
 
#4

AW: Problem mit Record-Parametern an MethodenPointer bzw. FunktionsPointer

  Alt 21. Jun 2021, 12:23
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
  Mit Zitat antworten Zitat
Andreas13

Registriert seit: 14. Okt 2006
Ort: Nürnberg
709 Beiträge
 
Delphi XE5 Professional
 
#5

AW: Problem mit Record-Parametern an MethodenPointer bzw. FunktionsPointer

  Alt 21. Jun 2021, 14:43
Vielen Dank, TiGü: Es funktioniert!
Nach Deiner Idee konnte ich den Aufruf sogar noch weiter vereinfachen, indem ich direkt MyFunktion(..) um den Eintrag Self: Pointer; erweitert habe:
Delphi-Quellcode:
Function MyFunktion(Self: Pointer; CONST Rec: DoubleDouble): DoubleDouble;
. . .
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...

Danke Dir noch einmal: Du hast mir sehr geholfen!
Gruß, Andreas
PS:
So funktionieren alle vier Varianten!
Grüße, Andreas
Wenn man seinem Nächsten einen steilen Berg hinaufhilft, kommt man selbst dem Gipfel näher. (John C. Cornelius)
  Mit Zitat antworten Zitat
Andreas13

Registriert seit: 14. Okt 2006
Ort: Nürnberg
709 Beiträge
 
Delphi XE5 Professional
 
#6

AW: Problem mit Record-Parametern an MethodenPointer bzw. FunktionsPointer

  Alt 21. Jun 2021, 17:00
Sorry, ich war wohl etwas voreilig und muß meine letzte pauschale Aussage etwas relativieren: 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 TTestObject.Create; ist nicht nötig.

Andreas
Grüße, Andreas
Wenn man seinem Nächsten einen steilen Berg hinaufhilft, kommt man selbst dem Gipfel näher. (John C. Cornelius)

Geändert von Andreas13 (21. Jun 2021 um 17:08 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.017 Beiträge
 
Delphi 12 Athens
 
#7

AW: Problem mit Record-Parametern an MethodenPointer bzw. FunktionsPointer

  Alt 21. Jun 2021, 18:07
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
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests

Geändert von himitsu (21. Jun 2021 um 19:21 Uhr)
  Mit Zitat antworten Zitat
Andreas13

Registriert seit: 14. Okt 2006
Ort: Nürnberg
709 Beiträge
 
Delphi XE5 Professional
 
#8

AW: Problem mit Record-Parametern an MethodenPointer bzw. FunktionsPointer

  Alt 21. Jun 2021, 19:15
Danke, Himitsu!
Ich werde versuchen, Deinen recht konzentrierten Code zu verstehen. Leider habe ich noch etliche Lücken bezüglich Generics, anonymer Methoden etc.
Gruß, Andreas
Grüße, Andreas
Wenn man seinem Nächsten einen steilen Berg hinaufhilft, kommt man selbst dem Gipfel näher. (John C. Cornelius)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.017 Beiträge
 
Delphi 12 Athens
 
#9

AW: Problem mit Record-Parametern an MethodenPointer bzw. FunktionsPointer

  Alt 21. Jun 2021, 19:28
Bei "reference to procedure" werden intern quasi die Generics verwendet ... du selbst hast hier nichts damit zu tun ... macht alles der Compiler von selbst.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
freimatz

Registriert seit: 20. Mai 2010
1.377 Beiträge
 
Delphi 11 Alexandria
 
#10

AW: Problem mit Record-Parametern an MethodenPointer bzw. FunktionsPointer

  Alt 22. Jun 2021, 16:05
Ja genau. Einfach "reference to" dazu und Hirn abschalten
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2   

Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 12:50 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz