Funktionszeiger einer C++-Memberfunktion an eine C-Funktion übergeben
-
Hallo Leute!
Ich habe eine C-Bibliothek geschrieben. eine C++-Anwendung soll auf diese Bibliothek zugreifen. Einige Funktionen der C-Bibliothek müssen per Callback eine Funktionen aus der C++-Anwendung aufrufen. Beim Versuch den entsprechenden Funktionszeiger an die Bibliothek zu übergeben, bekomme ich immer wieder Fehler und weiß nun nicht 100% wie ich diesen Callback-Mechanismus am besten realisieren soll. Ich habe schon verschiedene Forenbeiträge und Tutorials gelesen aber ich komme auf keinen grünen Zweig. Könnte mir jemand von euch bitte ein Beispiel für einen sollchen Callback-Mechanismus posten? Sonst verzweifel ich hier noch.Hier ist das Problem nochmal kurz und bündig:
Eine C++-Klasse soll, mit einer Funktion aus der C-Bibliothek, einen Funktionzeiger in der Bibliothek anlegen können. Damit dann Die Funktionen aus der C-Bibliothek die Funktion aus der C++-Klasse aufrufen können.Viele Grüße
Der Bauer
-
derBauer schrieb:
Einige Funktionen der C-Bibliothek müssen per Callback eine Funktionen aus der C++-Anwendung aufrufen.
Das als solches ist nicht das Problem, wenn es wirklich freie Funktionen, und nicht nicht-statische Methoden (Funktionen einer Klasse) sind. Den Letztere bestehen nicht aus einem, sondern 2 Zeigern.
Nehmen wir mal den folgenden Fall:
class Bar { public: void Foo(int a) { m_A = a; // tatsächlich: this->m_A = a; // <-- this kommt noch dazu... } private: int m_A; };
Ein alter Trick war es C-Callbacks...
a) bei der Registrierung des Callbacks einen void-Zeiger mitzugeben (Aus C++ wird dieser mit dem Instanzzeiger gesetzt).
b) Dem Callback um einen void-Zeiger ergänzen, bei dessen Aufruf der wert aus a übergeben wird.
c) In der C++ Bibliothek eine Freie Funktion als Wrapper zwischen zu hängen, die den void-Zeiger wieder auf den Instanzzeiger zurückwandelt.Der "Callback" für die obige Methode sähe dann in der C++ Bibliothek etwa so aus (Kann natürlich auch als statische Methode umgesetzt werden, soviel ich weiß gibt es hierzu auch C++ Konstrukte, nur arbeite ich schon recht lange nicht mehr mit C-Callbacks und daher müsste ich nachschauen ob bind & Co für C-Callbacks geeignet sind):
void BarFooCallback(int a, void * parameter) { Bar * bar = static_cast<Bar*>(parameter); bar->foo(a); }
-
Du kannst von C aus nicht so einfach eine C++-Funktion aufrufen. Der übliche Weg ist die Funktionssignatur in der C-Funktion vorzugeben.
Folgendes ist üblich:
extern "C"{ void __cdecl RegisterCallback(void (__cdecl *function)(void *), void *p); }
Man beachte das extern "C", damit C++ weiß wie es RegisterCallback aufzurufen hat und die 2 __cdecl, die die Callingconvention festlegen.
Der C++-Code muss nun einen Wrapper schreiben, der die eigentliche Funktion aufruft.
void __cdecl wrapper(void *p){ auto s = (MyStruct *)p; std::sort(s->start, s->end); }
Zu benutzen so:
struct MyStruct{ int *start, *end; }; void makeCallbackToSortArray(){ static int arr[] = {1,3,7,5,23,34,2,4}; static MyStruct s; s.start = arr; s.end = arr + sizeof arr / sizeof *arr; RegisterCallback(wrapper, &s); }
//mist, zu langsam
Es ist weiterhin üblich, dass RegisterCallback die letzte gespeicherte Callbackfunktion zurückgibt, sodass man mehrere Callbacks registrieren kann.
-
Vielen Dank ich werde es gleich mal testen