Ich habe einen leeren Zeiger, der von dlsym () zurückgegeben wurde. Ich möchte die Funktion aufrufen, auf die der leere Zeiger zeigt.
void *gptr = dlsym(some symbol..) ;
typedef void (*fptr)();
fptr my_fptr = static_cast<fptr>(gptr) ;
Ich habe auch reinterpret_cast
probiert, aber kein Glück, obwohl der C-Cast-Operator zu funktionieren scheint ..
Das Konvertieren eines void*
in einen Funktionszeiger direkt ist in C++ 98/03 nicht zulässig (sollte nicht mit einer der Umwandlungen kompiliert werden). Es wird in C++ 0x bedingt unterstützt (eine Implementierung kann das Verhalten definieren, und wenn es es definiert, muss es das tun, was der Standard sagt, dass es tun soll.) Ein void*
, wie durch den Standard C++ 98/03 definiert , sollte auf Objekte zeigen und keine Funktionszeiger oder Elementzeiger enthalten.
Zu wissen, dass das, was Sie tun, stark von der Implementierung abhängt, ist eine Option, die auf den meisten Plattformen kompiliert und funktionieren sollte (vorausgesetzt, 32-Bit-Zeiger, lang für 64-Bit), obwohl dies nach dem Standard eindeutig undefiniertes Verhalten ist:
void *gptr = dlsym(some symbol..) ;
typedef void (*fptr)();
fptr my_fptr = reinterpret_cast<fptr>(reinterpret_cast<long>(gptr)) ;
Und hier ist eine weitere Option, die kompilieren und funktionieren sollte, aber die gleichen Einschränkungen mit sich bringt wie oben:
fptr my_ptr = 0;
*reinterpret_cast<void**>(&my_ptr) = gptr;
Oder in Zeitlupe ...
// get the address which is an object pointer
void (*(*object_ptr))() = &my_ptr;
// convert it to void** which is also an object pointer
void ** ppv = reinterpret_cast<void**>(object_ptr);
// assign the address in the memory cell named by 'gptr'
// to the memory cell that is named by 'my_ptr' which is
// the same memory cell that is pointed to
// by the memory cell that is named by 'ppv'
*ppv = gptr;
Im Wesentlichen wird die Tatsache ausgenutzt, dass die Adresse des Funktionszeigers ein Objektzeiger [void (*(*object_ptr))()]
ist. Daher können Sie ihn mit reinterpret_cast
in einen beliebigen anderen Objektzeiger konvertieren: z. B. void**
. Wir können dann die Adresse (durch Dereferenzierung der Leere **) zum eigentlichen Funktionszeiger zurückverfolgen und dort den Wert des gptr speichern.
yuk - keinesfalls klar definierter Code - aber er sollte das tun, was Sie bei den meisten Implementierungen erwarten.
Beachten Sie, dass C++ 11 eine solche Konvertierung zulässt. Ab gcc 4.9 und darüber wird keine Warnung generiert: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57869 .
Siehe SO Diskussionen:
Ich fand diese (etwas hässliche) Lösung. gcc mit maximaler Warnstufe beschwert sich nicht. Dieses Beispiel ruft dlsym () (das einen void * zurückgibt) auf und gibt das Ergebnis in einem Funktionszeiger zurück.
typedef void (*FUNPTR)();
FUNPTR fun_dlsym(void* handle, const char* name) {
union {
void* ptr;
FUNPTR fptr;
} u;
u.ptr = dlsym(handle, name);
return u.fptr;
}
Man könnte die folgende Technik verwenden:
int (*fn)(int);
*(void **)(&fn) = dlsym(lib1, "function");
int result = (*fn)(3);
Oder
fn = (int (*)(int))dlsym(lib1, "function");
Zusammengestellt mit:
g++ -Wall -pedantic -std=c++11
Sie können dlsym
in eine Funktion umwandeln, die den erforderlichen Zeiger zurückgibt, und sie dann folgendermaßen aufrufen:
typedef void (*fptr)();
fptr my_fptr = reinterpret_cast<fptr (*)(void*, const char*)>(dlsym)(RTLD_DEFAULT, name);
PS. Das Umwandeln eines Funktionszeigers in einen anderen Funktionszeiger und das anschließende Aufrufen dieses Verhaltens ist undefiniert (siehe Punkt 7 in https://en.cppreference.com/w/cpp/language/reinterpret_cast ), damit es besser ist Um das Ergebnis von dlsym
in uintptr_t
und dann in den gewünschten Typ umzuwandeln:
fptr my_fptr = reinterpret_cast<fptr>(reinterpret_cast<uintptr_t>(dlsym(RTLD_DEFAULT, name)));
Dies wird in Visual Studio kompiliert, ohne dass die Umwandlung neu interpretiert wird:
void *ptr;
int (*func)(void) = (int(*)(void))ptr;
int num = func();