Hi,
nachdem lwip nun laeuft wollte ich ein kleines programm schreiben.
Leider scheitert es daran in meiner EchoClient Class einen Function
Pointer an lwip zu uebergeben...
Fehlermeldung:
../EchoClient.cpp:29:26: error: cannot convert 'std::_Mem_fn<signed char
(EchoClient::*)(void*, tcp_pcb*, signed char)>' to 'tcp_accept_fn {aka
signed char (*)(void*, tcp_pcb*, signed char)}' for argument '2' to
'void tcp_accept(tcp_pcb*, tcp_accept_fn)'
Pascal H. schrieb:> nachdem lwip nun laeuft wollte ich ein kleines programm schreiben.> Leider scheitert es daran in meiner EchoClient Class einen Function> Pointer an lwip zu uebergeben...
std::mem_fun gibt aber keinen Funktionszeiger zurück. Auf eine
nicht-statische Memberfunktion kann man gar keine C-Funktionszeiger
erzeugen. Wie auch? Es fehlt ja das Objekt.
Oft bieten C-Libraries, die mit Funktionspointern arbeiten, die
Möglichkeit, einen opaken Wert durchzureichen, d.h. diesen beim
Bekanntgeben des Funktionspointer mit anzugeben, und dieser Wert wird
beim Aufrufen der Funktion als ein Argument übergeben.
Damit kann man den this -Pointer transportieren.
Der Funktionspointer verweist auf eine statische Memberfunktion, die
wiederum erzeugt aus dem opaken Wert den fehlenden this-Pointer und kann
dann die nichtstatische Memberfunktion aufrufen.
Dabei geht natürlich einiges an Typsicherheit & Co. verloren, weil bei
der Operation "erzeuge this-Pointer aus opakem Wert" darauf vertraut
werden muss, daß dieser Wert tatsächlich die Adresse eines passenden
Objektes ist, aber wenn man diese ... Unschönheit verschmerzen kann,
lässt sich auf diesem Weg recht problemlos eine Schnittstelle zwischen
C-Funktionspointergebrauch und C++ nutzen.
Möchte man auf Nummer Sicher gehen, kann man sich natürlich auch eine
Klasse zur Verwaltung von im Zusammenhang mit Funktionspointern
verwendeten this-Pointern basteln, und die Pointer durch Nummern
referenzieren, die dann als opaker Wert genutzt werden. Das ist halt
mehr Aufwand als die oben beschriebene Methode, aber dafür auch
sicherer, weil wenn Müll anstelle des gewünschten opaken Werts ankommt,
dieser klar erkannt werden kann.
Vielen Dank fuer die Anworten.
Ich fand die Idee recht schoen alles was den EchoClient angeht in dieser
Klasse zu kapseln. Klar koennte ich einfach eine globale accept function
bereitstellen aber das ist immer alles so verwoben dann.
Ich werde mir die Idee mit dem uebergeben eines this pointers in einer
wrapper Klasse mal ansehen.
Rufus Τ. F. schrieb:> Der Funktionspointer verweist auf eine statische Memberfunktion, die> wiederum erzeugt aus dem opaken Wert den fehlenden this-Pointer und kann> dann die nichtstatische Memberfunktion aufrufen.
Die Funktion muss für den Aufruf von C aus als extern "C" deklariert
sein, was für statische Memberfunktionen nicht möglich ist. Man braucht
eine freie Funktion.
Ich habe mir jetzt mal das hier gebastelt
Auch wenn es mir nicht gefaellt mit der statischen Funktion.
Wenn ich das umschiffen wollen wuerde, muesste ich das lwip struct
welches die callback functions haelt erweitern und den this pointer dort
mitschleifen oder?
Also ich hab das Programm jetzt soweit erweitert, dass ich mit telnet in
die globalAccept function komme. Nur leider stimmt der newpcb pointer
mit dem in der map nicht ueberein :(
Keine Ahnung was lwip da intern noch umkopiert, somit ist meine referenz
futsch. Habt ihr eine Idee?
Pascal H. schrieb:> Wenn ich das umschiffen wollen wuerde, muesste ich das lwip struct> welches die callback functions haelt erweitern und den this pointer dort> mitschleifen oder?
Und du müßtest lwip so umbauen, dass es eine C++-Memberfunktion (unter
Nutzung dieses Zeigers) aufzurufen statt eine C-Funktion.
Generell: Warum so umständlich mit einer Map? Nimm doch einfach arg für
den this-Zeiger. Für genau solche Sachen ist das doch da.
Übrigens: Bist du dir sicher, dass m_pcb = tcp_listen(m_pcb) eine gute
Idee ist? So wie ich das verstehe, überschreibst du dir damit den
einzigen Zeiger, den du auf deine mit tcp_new() erstellte pcb hast.
Rolf Magnus schrieb:> Die Funktion muss für den Aufruf von C aus als extern "C" deklariert> sein, was für statische Memberfunktionen nicht möglich ist. Man braucht> eine freie Funktion.
Das stimmt in diesem fall nicht. Extern c deaktiviert nur das name
mangeling und ist für den Linker relevant wenn aus einer c
compilationsunit ein Symbol einer C++ unit aufgelöst werden soll. Da das
Referenzieren und somit die Namensauflösung in einer C++ unit
statfindet, ist das name mangeling kein Problem und das extern c somit
überflüssig und das verwenden von statischen Memberfunktionen möglich.
Die C unit bekommt ja nur einen pointer, und wie die funktion auf welche
dieser zeigt hiess ist der reichlich egal.
Daniel A. schrieb:> Extern c deaktiviert nur das name mangeling und ist für den Linker relevant> wenn aus einer c compilationsunit ein Symbol einer C++ unit aufgelöst> werden soll.
Nein. Es kümmert sich auch noch um weitere Dinge, wie die
Aufrufkonventionen, also z.B. wie Parameter übergeben werden - eben
alles, was für den korrekten Aufruf einer Funktion zu beachten ist.
Es funktioniert zwar bei vielen Compilern tortzdem ohne, da die
Aufrufkonventionen in C und in C++ oft gleich sind, aber das muss nicht
so sein.
Aus ISO C++98 (hab nix neueres, aber da wird das nicht anders sein):
All function types, function names, and variable names have a language
linkage. [Note: Some of the properties associated with an entity with
language linkage are specific to each implementation and are not
described here. For example, a particular language linkage may be
associated with a particular form of representing names of objects and
functions with external linkage, or with a particular calling
convention, etc.] The default language linkage of all function types,
function names, and variable names is C++ language linkage. Two function
types with different language linkages are distinct types even if they
are otherwise
identical.