Files |  Tutorials |  Articles |  Links |  Home |  Team |  Forum |  Wiki |  Impressum

Aktuelle Zeit: Mi Jul 16, 2025 12:01

Foren-Übersicht » Programmierung » Allgemein
Unbeantwortete Themen | Aktive Themen



Ein neues Thema erstellen Auf das Thema antworten  [ 11 Beiträge ] 
Autor Nachricht
 Betreff des Beitrags: Frage zu Callback-Prozeduren
BeitragVerfasst: Di Jun 24, 2008 13:47 
Offline
DGL Member
Benutzeravatar

Registriert: Mo Apr 25, 2005 17:51
Beiträge: 464
*moep*

Hiho ihr Delphi-Asse,

ich habe mal eine Frage, warum folgendes nicht funktioniert:

Code:
  1. TLineCallback = procedure(line : TLine);
  2. TPLineCallback = ^TLineCallback;
  3.  
  4.  
  5. procedure setLineCallback(fn : TPLineCallback);
  6. begin
  7.    lineFn:= fn;
  8. end;
  9.  
  10.  
  11. ...
  12.  
  13.  
  14. if (lineFn <> nil) then
  15.   lineFn^(pObj);


Das ganze ist etwas zusammengefasst auf das Wesentliche. Kompilieren tut es, aber sobald ich die Callback-Funktion rufe, gibts nen Speicheradressenfehler.
Es funktioniert, wenn ich das lineFn als TLineCallback (also nicht die Pointer-Variante) überall nehme und bei dem if dann (if (@lineFn <> nil) benutze.

Code:
  1. TLineCallback = procedure(line : TLine);
  2.  
  3.  
  4. procedure setLineCallback(fn : TLineCallback);
  5. begin
  6.    lineFn:= fn;
  7. end;
  8.  
  9.  
  10. ...
  11.  
  12.  
  13. if (@lineFn <> nil) then
  14.   lineFn(pObj);

Also von daher hab ich schon nen Workaround. Aber trotzdem die Frage: warum geht das erste nicht???

_________________
__________
"C++ is the best language for garbage collection principally because it creates less garbage." Bjarne Stroustrup


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Di Jun 24, 2008 13:52 
Offline
DGL Member
Benutzeravatar

Registriert: Do Sep 02, 2004 19:42
Beiträge: 4158
Programmiersprache: FreePascal, C++
Weil du mit
Code:
  1. TLineCallback = procedure(line : TLine);

schon eine art Pointer deklarierst. Ich weiss nicht, was Delphi dann genau tut, aber das reicht eigentlich aus.

Gruß Lord Horazont

_________________
If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung.
current projects: ManiacLab; aioxmpp
zombofant networkmy photostream
„Writing code is like writing poetry“ - source unknown


„Give a man a fish, and you feed him for a day. Teach a man to fish and you feed him for a lifetime. “ ~ A Chinese Proverb


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Di Jun 24, 2008 15:03 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 05, 2002 10:35
Beiträge: 4234
Wohnort: Dortmund
Das ist nicht nur eine Art Pointer. Das ist sogar Einer. ;)

In C++ wäre das folgendes
Code:
  1. TLineCallback = procedure(line : TLine); // pascal
  2.  
  3. void (*TLineCallback)(TLine line); // c++




Code:
  1. TPLineCallback = ^TLineCallback;

Ist ein Pointer auf einen Pointertyp (TLineCallback). Solltest du nur machen, wenn du diesen als optionalen Parameter (Referenz) einer Methode machen willst. Also, dass die Methode diesen Parameter setzen kann. Denn eigentlich musst du bei so etwas dann auch einen Pointer auf eine Variable vom Typen TLineCallback übergeben. Ein var parameter geht dafür aber auch. Dann hat man mit dem Pointer nicht direkt etwas zu tun.


PS: Achte bitte auf eventuelle Aufrufkonventionen. Solange es nur innerhalb von einer Pascalanwendung benutzt wird ist es unkritisch. Ansonsten lieber immer eine angeben.

PPS: Achja. Ich hab das Thema mal hierhin verschoben.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Mi Jun 25, 2008 08:04 
Offline
DGL Member

Registriert: Mo Dez 20, 2004 08:58
Beiträge: 442
Wohnort: Mittweida (Sachsen)
Einen Hinweis auf die Zeigernatur einer Callback-Funktion/Prozedur/Methode fiefert auch die Tatsache, dass man bei Freepascal bei der Zuweisung auf eine Variable ein @voranstellen muss (Ausser im Delphi-Kompatibilitätsmodus). Delph erkennt, dass man an dieser Stelle eigentlich einen Zeiger auf die Methode übergeben will, FreePascal hält sich hier enger an die DelphiLanguage.
Beispiel:
Code:
  1.  
  2. Type
  3.   TMyProc=Procedure(Sender: TObject);
  4.  
  5.   TMyClass=Class(TObject)
  6.    oFMyProc: TMyProc; //Dies ist ein Zeiger auf eine Prozedur.
  7.    constructor Create;
  8.   End;
  9.  
  10.   Procedure RealerCallback(Sender: TObject);
  11.   Begin
  12.   End;
  13.  
  14. Implementation
  15. //Delphi
  16.   Constructor TMyClass.Create;
  17.   Begin
  18.     Inherited;
  19.     oFMyProc:=RealerCallback; //Delphi erkennt, dass die Adresse zugewiesen werden soll
  20.   End;
  21.  
  22. //FreePascal
  23.   Constructor TMyClass.Create;
  24.   Begin
  25.     Inherited;
  26.     oFMyProc:=@RealerCallback; //FreePascal nimmts genau. Ohne @ kommt ein Compilerfehler
  27.   End;
  28.  
  29.  

_________________
Manchmal sehen Dinge, die wie Dinge aussehen wollen, mehr wie Dinge aus, als Dinge.
<Esmerelda Wetterwax>
Es kann vorkommen, dass die Nachkommen trotz Abkommen mit ihrem Einkommen nicht auskommen und umkommen.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Mi Jun 25, 2008 09:00 
Offline
DGL Member
Benutzeravatar

Registriert: Mo Apr 25, 2005 17:51
Beiträge: 464
Ah ok danke.
Wenn das schon normal ein Zeiger ist, warum kann ich es dann nicht auf nil testen? Weil das war das eigentliche Probleme. Ich will testen, ob wirklich eine Callback-Funktion gesetzt ist. Und wenn ich das TLineCallback nehme, dann gibt das einen Compilefehler. Daher kam ich erst auf die "Idee" mit dem ^TLineCallback.

@Lossy: danke für den Hinweis, aber ich nutze das nur Delphi-Intern. Geht nicht über eine DLL oder sowas.


MfG Pellaeon

_________________
__________
"C++ is the best language for garbage collection principally because it creates less garbage." Bjarne Stroustrup


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Mi Jun 25, 2008 09:36 
Offline
DGL Member
Benutzeravatar

Registriert: Mi Jan 31, 2007 18:32
Beiträge: 150
Programmiersprache: Pascal
so müsste es eigentlich gehen :

Code:
  1.  
  2. TMyProc = Procedure(Sender: TObject);
  3. .
  4. .
  5. .
  6. oFMyProc: TMyProc;
  7. .
  8. .
  9. .
  10. Begin
  11.   if Assigned(oFMyProc) then oFMyProc(Sender);
  12. End;
  13.  


das würde die procedure ausführen wenn eine zugewiesen ist.... hoffe es hilft dir weiter


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Mi Jun 25, 2008 09:55 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 05, 2002 10:35
Beiträge: 4234
Wohnort: Dortmund
Zum Überprüfen auf nil gibt es verschiedene Wege. Entweder über die "Methode" Assigned oder über den @Operator / Methode Addr. All die Sachen werden vom Compiler in inline code verwandelt und sind wie normale abfragen. In deinem Fall handelt es sich um eine Variable auf eine Methode. Beim Zuweisen einer solchen Variable kann man in Delphi ohne @Arbeiten. Beim Auslesen ohne Operator versucht er aber die Methode auszuführen was dann zu einem Kompilerfehler führen kann. Bei Methoden ohne Parameter und mit einem Pointer als Rückgabewert lässt es sich aber übersetzen. Dann wird aber die Methode ausgeführt.

Normal gibt @ oder Addr die Adresse einer Variable zurück. Bei Funktionspointern liefert er dir aber die Adresse der enthaltenen Funktion zurück. Und nicht wie man erwarten könnte die Adresse der Variable. Die bekommt er erst, wenn man 2 Mal die Adresse erfragt. Also @@ oder sonst welcher Kombination mit Addr.

[edit] Man bin ich heute wieder langsam. Aber evtl. hilft es ja ein bisschen fürs Verständniss.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Mi Jun 25, 2008 14:54 
Offline
DGL Member

Registriert: Mo Dez 20, 2004 08:58
Beiträge: 442
Wohnort: Mittweida (Sachsen)
Um mal bei Deinem Beispiel zu bleiben:

Code:
  1.  
  2. TLineCallback = procedure(line : TLine);
  3.  
  4.  
  5. procedure setLineCallback(fn : TLineCallback);
  6. begin
  7.    lineFn:= fn;
  8. end;
  9. .......
  10.  
  11. if (@lineFn <> nil) then //hier liegt der Fehler
  12. if (lineFn <> nil) then //so isses richtig
  13.   lineFn(pObj);
  14.  
  15.  

@linefn ist IMMER <>Nil, denn das ist je die Adresse, wo Dein Zeiger gespeichert ist. Da dies aber ein Member Deiner Klasse ist, wird dafür schon im Konstruktor Speicher angelegt und zugewiesen (i.d.R.: über Offsetwerte aus der Typbeschreibung, führt hier aber zu weit). Du willst aber wissen, ob in Deinem Member ein sinnvoller Wert drinsteht, Dich interessiert der Inhalt des Zeigers.
Delphi ist bei Methodenzeigern ähnlich wie bei Instanzzeigern schlau genug, bei Bedarf selber zu dereferenzieren.

_________________
Manchmal sehen Dinge, die wie Dinge aussehen wollen, mehr wie Dinge aus, als Dinge.
<Esmerelda Wetterwax>
Es kann vorkommen, dass die Nachkommen trotz Abkommen mit ihrem Einkommen nicht auskommen und umkommen.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Mi Jun 25, 2008 15:16 
Offline
DGL Member
Benutzeravatar

Registriert: Mo Apr 25, 2005 17:51
Beiträge: 464
Sidorion hat geschrieben:
Um mal bei Deinem Beispiel zu bleiben:

Code:
  1.  
  2. TLineCallback = procedure(line : TLine);
  3.  
  4.  
  5. procedure setLineCallback(fn : TLineCallback);
  6. begin
  7.    lineFn:= fn;
  8. end;
  9. .......
  10.  
  11. if (@lineFn <> nil) then //hier liegt der Fehler
  12. if (lineFn <> nil) then //so isses richtig
  13.   lineFn(pObj);
  14.  
  15.  

@linefn ist IMMER <>Nil, denn das ist je die Adresse, wo Dein Zeiger gespeichert ist. Da dies aber ein Member Deiner Klasse ist, wird dafür schon im Konstruktor Speicher angelegt und zugewiesen (i.d.R.: über Offsetwerte aus der Typbeschreibung, führt hier aber zu weit). Du willst aber wissen, ob in Deinem Member ein sinnvoller Wert drinsteht, Dich interessiert der Inhalt des Zeigers.
Delphi ist bei Methodenzeigern ähnlich wie bei Instanzzeigern schlau genug, bei Bedarf selber zu dereferenzieren.


Genau das habe ich ja gedacht, das ist aber falsch^^. Wo bei dir steht "hier liegt der Fehler", so ist es korrekt und wo bei dir richtig steht, das gibt einen Compilefehler^^
Begründung siehe der Post von Lossy :) Man lernt halt nie aus^^ Thx


MfG Pellaeon

_________________
__________
"C++ is the best language for garbage collection principally because it creates less garbage." Bjarne Stroustrup


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Do Jun 26, 2008 08:53 
Offline
DGL Member

Registriert: Mo Dez 20, 2004 08:58
Beiträge: 442
Wohnort: Mittweida (Sachsen)
Also ich programmier jetzt schon Jahre mit Delphi und nutze intensiv Callbacks, sowohl Procedure(), als auch Proccedure() of Object und habe noch NIE ein @ einsetzen müssen (ausser bei Systemrufen wie SetWindowLong, aber das ist ein anderes Pflaster). Der Fehler muss woanders liegen. Wie hast Du denn Dein lineFn deklariert?

[edit] falls Du mit FreePascal arbeitest, musst Du ggf. den @-Operator doch einsetzen, ähnlich wie bei der Zuweisung. Kann ich aber jetzt nicht nachvollziehen, weil ich kein FreePascal dahab.[/edit]

_________________
Manchmal sehen Dinge, die wie Dinge aussehen wollen, mehr wie Dinge aus, als Dinge.
<Esmerelda Wetterwax>
Es kann vorkommen, dass die Nachkommen trotz Abkommen mit ihrem Einkommen nicht auskommen und umkommen.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Do Jun 26, 2008 10:45 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 05, 2002 10:35
Beiträge: 4234
Wohnort: Dortmund
Sidorin du hast in so fern recht, wenn du sagst, dass man in Delphi für Funktionspointer auch ohne @Operator auskommt. Das stimmt vollkommen. Die Funktionspointer kann man direkt zuweisen, auslesen. Allerdings direkt vergleichen geht nicht, denn dann versucht er die Methode auszuführen. Man muss also Delphi irgendwie sagen, dass er den Funktionspointer benutzen soll. Also über Assigned, @ oder Addr. Assigned prüft obendrein selber noch auf nil oder nicht.

Folgender Code aus meinem Delphi 7.
Code:
  1. procedure TForm1.FormCreate(Sender: TObject);
  2. var
  3.   Notify: TNotifyEvent;
  4. begin
  5.   Notify := FormCreate;
  6.   Notify := nil;
  7.  
  8.   if Notify = nil then  // Compilerfehler
  9.     ShowMessage('"Notify = nil" = nil');
  10.  
  11.   if Addr(Notify) = nil then  // Message wird angezeigt
  12.     ShowMessage('"Addr(Notify) = nil" = nil');
  13.  
  14.   if @Notify = nil then  // Message wird angezeigt
  15.     ShowMessage('"@Notify = nil" = nil');
  16.  
  17.   if @@Notify = nil then  // keine Messagebox
  18.     ShowMessage('"@@Notify = nil" = nil');


Wenn man neben dem Notify auch noch einen Integer auf den Stack packt und sich die Hexwerte von @@Notify und @IntegerWert anschaut, dann ist der Wert nur ein paar Byte unterschiedlich. Bei @Notify hingeben ziemlich stark.

@@IntegerWert läuft hingegen auf einen Compilerfehler hinaus, da er gerne eine Variable haben möchte.

PS: Ich will nicht ausschließen, dass es irgendwo eine Option gibt oder, dass Delphi in der ein oder anderen Version dort etwas anderes macht.


Nach oben
 Profil  
Mit Zitat antworten  
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Ein neues Thema erstellen Auf das Thema antworten  [ 11 Beiträge ] 
Foren-Übersicht » Programmierung » Allgemein


Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 16 Gäste


Du darfst keine neuen Themen in diesem Forum erstellen.
Du darfst keine Antworten zu Themen in diesem Forum erstellen.
Du darfst deine Beiträge in diesem Forum nicht ändern.
Du darfst deine Beiträge in diesem Forum nicht löschen.
Du darfst keine Dateianhänge in diesem Forum erstellen.

Suche nach:
Gehe zu:  
  Powered by phpBB® Forum Software © phpBB Group
Deutsche Übersetzung durch phpBB.de
[ Time : 0.009s | 14 Queries | GZIP : On ]