PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : [C++] Cast von Funktionspointern



manjo
26-05-2004, 17:40
Hallo!

Ich nutze eine C-Library in C++. Diese ist alles andere als sauber programmiert - geht aber nicht anders, diese muss es sein.
Die entsprechenden Headerfiles sind mit extern "C" includiert. Aus dieser Library moechte ich eine Funktion mit folgendem Prototyp aufrufen:

int LibFkt( int para1, int para2, int (*FktPointer)() );

Der FktPointer zeigt bei jedem Aufruf dieser LibFkt auf eine andere Funktion. Die Funktion, auf die FktPointer zeigt, hat verschiedene Uebergabeparameter:

int Funktion1( int fpara1, fpara2 );
int Funktion2( int gpara1 );

Nun rufe ich die LibFkt wie folgt auf:

LibFkt(Para1,Para2,&Funktion1);
LibFkt(Para11,Para22,&Funktion2);

C++ meckert nun wohl auch zu recht,

invalid conversion from `int (*)(int, int)' to `int (*)()

Was nun? Wie bekomme ich es hin, dass ich die LibFkt trotzdem benutzen kann? Kann ich die Uebergabeparameterliste der Funktion, die hinter dem Funktionspointer steht, casten?

Viele Gruesse,

Manjo.

locus vivendi
27-05-2004, 21:29
Meines Wissens kannst du reinterpret_cast benutzen, um Funktionszeiger zu casten. Zumindest wird dein Compiler das übersetzen. Portabel dürfte das aber nur sein wenn du von einem Funktionszeiger-Typ auf den ursprünglichen Funktionszeiger-Type castest. Also folgendes z.B. ist m.E. NICHT portabel, weil void* ein Zeiger auf ein Objekt (nicht Funktion) unbekannten Typs ist:

void (*pfunc1)(int) = ...;
void* p = (void*) pfunc1;
void (*pfunc2)(int) = reinterpret_cast<void (*)(int)>(p);

In der Praxis funktionieren solche casts aber z.B. auf GNU/linux weil es u.a. eine Posix kompatible Funktion gibt die das braucht.

Eine definitive Antwort kann ich leider auch nicht geben.

locus vivendi
28-05-2004, 07:25
Ich muss mich korrigieren: Das Beispiel kompiliert noch nicht einmal. Auch in der dritten Zeile brauch man einen old-style cast.

manjo
28-05-2004, 14:29
Hallo!

Nun habe ich zum Problem eine Loesung gefunden:

Funktionspointer werden in C++ wie jeder andere Datentyp behandelt. Z.B.

int(*)(int,int)

Damit ist auch logisch, dass

int(*)(int,int) != int(*)()

ist. Also muss hier gecastet werden wie folgt:

int(*FktPointer1)(int, int);
int(*FktPointer2)();

FktPointer2 = ( int (*)() )FktPointer1;

So geht's also!

Gruss, Manjo.

locus vivendi
28-05-2004, 15:59
Bitte trotzdem beachten was ich geschrieben hatte. Erstens solltest du explizit reinterpret_cast verwenden, um deutlich zu machen, das es sich hier um eine potentiell gefährliche Angelegenheit handelt. Zweitens, deinem ersten Posting entnehme ich das die Funktion LibFkt die als Funktionszeiger übergeben Funktion aufruft. Das heißt, du darfst nur solche Zeiger übergeben deren ursprünglicher Typ (vor den ganzen Casts) tatsächlich den Typ int (*)() haben. Das heißt, dein Problem ist vermutlich noch nicht gelöst, wenn du tatsächlich Funktionen mit unterschiedlichem Typ aufrufen möchtest.

Tipp: Schau dich besser um wie du eine Funktion kapseln kannst, so daß Funktionen unterschiedlichen Typs auf die gleiche Weise aufgerufen werden können.

manjo
28-05-2004, 21:33
Hallo!


Nun, reinterpret_cast kann ich schon noch einbauen.

Die Sache ist um einiges komplizierter, als es hier erscheint. Die Details alle aufzuzaehlen, wuerde mir zu lange dauern. Also eine Kurzfassung:

Die "LibFkt" registriert die Funktion, deren Funktionspointer uebergeben wird, fuer bestimmte Ereignisse in einem System. Anhand der Parameter weiss die LibFkt fuer welche Ereignisse diese Funktion registriert werden muss. Der Aufruf der Funktion erfolgt dann automatisch mit den richtigen Parametern.

Hinzu kommt, dass wir hier ein gemischtes System aus C++ und ANSI-C haben. Also ein nahezu perfektes Chaos!

Gruss,

Manjo