web-dev-qa-db-fra.com

Pointeurs de fonction exprimés en C++

J'ai un pointeur vide renvoyé par dlsym (), je veux appeler la fonction indiquée par le pointeur vide . Je fais donc une conversion de type en convertissant:

void *gptr = dlsym(some symbol..) ;
typedef void (*fptr)();
fptr my_fptr = static_cast<fptr>(gptr) ;

J'ai aussi essayé reinterpret_cast mais pas de chance, bien que l'opérateur de casting C semble fonctionner.

34
sud03r

La conversion d'un void* en un pointeur de fonction directement n'est pas autorisée (ne doit pas être compilée à l'aide de l'un des conversions) en C++ 98/03. Il est pris en charge de manière conditionnelle dans C++ 0x (une implémentation peut choisir de définir le comportement et si elle le définit, elle doit alors agir comme le veut la norme. Un void*, tel que défini par la norme C++ 98/03 , était destiné à pointer sur des objets et non à contenir des pointeurs de fonction ou des membres. 

Sachant que ce que vous faites est fortement dépendant de la mise en œuvre, voici une option qui devrait compiler et fonctionner (en supposant que les pointeurs 32 bits soient longs, 64 bits) sur la plupart des plateformes, même s'il s'agit clairement d'un comportement indéfini selon la norme:

void *gptr = dlsym(some symbol..) ;
typedef void (*fptr)();
fptr my_fptr = reinterpret_cast<fptr>(reinterpret_cast<long>(gptr)) ;

Et voici une autre option qui devrait compiler et fonctionner, mais comporte les mêmes mises en garde que ci-dessus:

fptr my_ptr = 0;
*reinterpret_cast<void**>(&my_ptr) = gptr; 

Ou, au ralenti ...

// 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;  

Il exploite essentiellement le fait que l'adresse du pointeur de la fonction est un pointeur d'objet [void (*(*object_ptr))()]. Nous pouvons donc utiliser reinterpret_cast pour le convertir en un autre pointeur d'objet: tel que void**. Nous pouvons ensuite suivre l'adresse (en déréférencant le vide **) jusqu'au pointeur de la fonction réelle et y stocker la valeur du gptr.

yuk - pas de code bien défini - mais il devrait faire ce que vous attendez de la plupart des implémentations.

47
Faisal Vali
8
Amir Kirsh

J'ai trouvé cette solution (un peu moche). gcc avec niveau d’avertissement maximum ne se plaint pas. Cet exemple appelle dlsym () (qui renvoie un void *) et renvoie le résultat dans un pointeur de fonction.

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

On pourrait utiliser la technique suivante:

int (*fn)(int);
*(void **)(&fn) = dlsym(lib1, "function");
int result = (*fn)(3);

Ou

fn = (int (*)(int))dlsym(lib1, "function");

Compilé avec:

g++ -Wall -pedantic -std=c++11
0
Iurii

Cela compile dans Visual Studio sans utiliser le cast de réinterprétation:

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