wake-up-neo.com

Funktionszeiger, die in C++ gießen

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 ..

34
sud03r

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.

47
Faisal Vali
8
Amir Kirsh

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;
}
1
BrunoLevy

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
0
Iurii

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)));
0

Dies wird in Visual Studio kompiliert, ohne dass die Umwandlung neu interpretiert wird:

void *ptr;
int (*func)(void) = (int(*)(void))ptr;
int num = func();
0
Andrew Best