2009-07-08 11 views
28

Tengo un puntero de vacío devuelto por dlsym(), quiero llamar a la función apuntada por el puntero de vacío. por lo que una conversión de tipos por colada:Punteros de función fundición en C++

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

también he intentado reinterpret_cast pero no hubo suerte, aunque el operador C elenco parece funcionar ..

+0

uf, su formato tienen desordenar. –

+0

Realmente tiene que arreglar ese código para que podamos leerlo. ¿Qué pasa con las barras diagonales? ¿Estás intentando escribir my_fptr = static_cast (gptr)? –

+1

Se solucionó el problema de formato. En lugar de usar las etiquetas HTML, use los botones de formato que están disponibles. – Naveen

Respuesta

45

Conversión de un void* a un puntero de función directamente no está permitido (no debe compilarse utilizando ninguno de los moldes) en C++ 98/03. Se admite de forma condicional en C++ 0x (una implementación puede elegir definir el comportamiento y, si lo define, debe hacer lo que el estándar dice que debería hacer. A void*, como se define en la norma C++ 98/03 , estaba destinado para apuntar a objetos y no para contener punteros a funciones o punteros miembros.

Sabiendo que lo que está haciendo es en gran medida dependiente de la implementación, aquí es una opción que debe recopilar y trabajo (suponiendo 32 punteros de bits, el uso a largo tiempo de 64 bits) en la mayoría de las plataformas, a pesar de que es claramente un comportamiento no definido de acuerdo a la norma:

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

y aquí es otra opción que se debe recopilar y trabajo, pero Carr IES las mismas advertencias con ella como lo anterior:

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

O, en cámara lenta ...

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

En esencia, aprovecha el hecho de que la dirección del puntero de función es un puntero de objeto [void (*(*object_ptr))()] - entonces podemos usar reinterpret_cast para convertirlo a cualquier otro puntero de objeto: como void**. Luego podemos seguir la dirección hacia atrás (desmarcando el vacío **) al puntero de la función real y almacenar allí el valor del gptr.

yuk - de ninguna manera código bien definido - pero debe hacer lo que espera que haga en la mayoría de las implementaciones.

+1

Espero que esto sea todo: el casting de C++ cumple con los estándares, el casting C es compatible con los requisitos de las llamadas a bibliotecas compartidas de POSIX. –

+0

Incluso el lanzamiento explícito de estilo C no es necesario para realizar la conversión o incluso compilar: el molde de estilo C se define en términos de los otros moldes (con una característica adicional menor con respecto a la accesibilidad de la clase base). –

+7

Como nota al margen, una mejor opción de un tipo para usar en un lanzamiento intermedio podría ser 'size_t'; generalmente es lo suficientemente grande como para caber un puntero en cualquier plataforma, aunque eso tampoco está garantizado. Mejor aún, use ''/'' header y 'intptr_t' typedef en él donde esté disponible (C99, C++ TR1, C++ 0x). –

-6

Esto puede ayudarlo. Imprime "Hola".

#include <iostream> 

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

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

o puede hacerlo:

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

donde & hola se sustituye por el comando dlsym.

+1

¡Voy a estar * asombrado * si eso es útil! –

+0

La razón por la que está funcionando es porque no está pasando por un puntero 'void *'. –

+1

Después de la edición, ¿verdad? Y el código parece funcionar. (Aunque no soy un experto, ¿entonces esto podría funcionar, pero en realidad no está definido?) – Mike

2

Esto compila en Visual Studio sin usar reinterpretar reparto:

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

Podría compilar, pero ** ** dará como resultado un comportamiento indefinido (según lo descrito por las especificaciones C) –

+2

¿Eso es realmente sin ' reinterpret_cast'? ¿Qué modelo elegirá el compilador? –

+5

Estás haciendo un molde de estilo c, que en realidad es un molde de reinterpretación en este caso. – WestleyArgentum

0

yo encontramos este (un poco feo) solución. gcc con nivel de advertencia máximo no se queja. Este ejemplo llama a dlsym() (que devuelve un vacío *) y devuelve el resultado en un puntero de función.

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

Eso funciona si la unidad de compilación es C pero no C++ 11 y más tarde ya que es un comportamiento indefinido: http://stackoverflow.com/questions/11373203/accessing-inactive-union-member-undefined-behavior – Vitali