2009-07-08 8 views
28

J'ai un pointeur vide retourné par dlsym(), je veux appeler la fonction pointée par le pointeur vide. donc je fais une conversion de type par coulée:Les pointeurs de fonction coulent en C++

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 cast C semble fonctionner ..

+0

ugh, la mise en forme ont gâcher. –

+0

Vous devez vraiment corriger ce code pour pouvoir le lire. Qu'est-ce qui se passe avec les barres obliques? Essayez-vous de taper my_fptr = static_cast (gptr)? –

+1

Correction du problème de formatage. Au lieu d'utiliser les balises HTML, utilisez les boutons de formatage disponibles. – Naveen

Répondre

45

Conversion d'un void* à un pointeur de fonction directement n'est pas autorisé (ne devrait pas compiler en utilisant l'un des moulages) en C++ 98/03. Il est supporté sous condition en C++ 0x (une implémentation peut choisir de définir le comportement et si elle le définit, elle doit faire ce que la norme dit qu'elle devrait faire.) void*, comme défini par la norme C++ 98/03 Nous voulions pointer vers des objets et ne pas contenir de pointeurs de fonction ou de membres

Sachant que ce que vous faites est fortement dépendant de l'implémentation, voici une option qui devrait compiler et fonctionner (en supposant que les pointeurs 32 bits, utilisent long long 64 bits) sur la plupart des plates-formes, même si ce comportement est clairement définie selon la norme:

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

et est une autre option ici qui devrait compiler et le travail, mais carr s les mêmes mises en garde avec elle comme ci-dessus:

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

Ou, en mouvement lent ...

// 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 fonction est un pointeur d'objet [void (*(*object_ptr))()] - nous pouvons donc utiliser reinterpret_cast pour le convertir en n'importe quel autre pointeur d'objet: tel que void**. Nous pouvons ensuite suivre l'adresse (en déréférenciant le vide **) au pointeur de fonction réel et y stocker la valeur du gptr. Yu - en aucun cas un code bien défini - mais il devrait faire ce que vous attendez de lui pour la plupart des implémentations.

+1

Je m'attends à ce que ce soit le cas - le casting C++ est conforme à la norme, la conversion C est rétrocompatible avec les exigences des appels de bibliothèque partagée POSIX. –

+0

Même la distribution explicite de style C n'est pas nécessaire pour effectuer la conversion ou même compiler - la distribution de style C est définie en termes d'autres conversions (avec une fonctionnalité supplémentaire mineure concernant l'accessibilité de la classe de base). –

+7

En guise de remarque, un meilleur choix d'un type à utiliser dans un casting intermédiaire pourrait être 'size_t' - il est généralement assez grand pour contenir un pointeur sur n'importe quelle plate-forme, même si cela n'est pas garanti non plus. Mieux encore, utilisez ''/'' header et 'intptr_t' typedef là où c'est disponible (C99, C++ TR1, C++ 0x). –

-6

Cela peut vous aider. Il imprime "Bonjour".

#include <iostream> 

void hello() 
{ 
    std::cout << "Hello" << std::endl; 
} 

int main() { 
    typedef void (*fptr)(); 
    fptr gptr = (fptr) (void *) &hello; 
    gptr(); 
} 

OU vous pouvez faire:

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

où & bonjour est remplacé par la commande dlsym.

+1

Je vais être * étonné * si c'est utile! –

+0

La raison pour laquelle cela fonctionne est parce que vous ne passez pas par un pointeur 'void *'. –

+1

Après l'édition, il est, non? Et le code semble fonctionner. (Bien que je ne sois pas un expert, alors peut-être que cela fonctionne, mais est en fait indéfini?) – Mike

2

Cette compile dans Visual Studio sans utiliser réinterprètent cast:

void *ptr; 
int (*func)(void) = (int(*)(void))ptr; 
int num = func(); 
+2

Peut compiler, mais ** entraînera ** un comportement indéfini (comme décrit par les spécifications C). –

+2

Est-ce vraiment sans ' reinterpret_cast'? Quel cast le compilateur choisira-t-il? –

+5

Vous effectuez une distribution de style c, qui est effectivement une réinterprétation de la distribution dans ce cas. – WestleyArgentum

0

Je trouve cela (un peu laid) solution. Gcc avec le 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; 
} 
+0

Cela fonctionne si l'unité de compilation est C mais pas C++ 11 et plus tard car il s'agit d'un comportement indéfini: http://stackoverflow.com/questions/11373203/accessing-inactive-union-member-undefined-behavior – Vitali

Questions connexes