Punteros de función de fundición en C ++

Tengo un puntero de vacío devuelto por dlsym (), quiero llamar a la función apuntada por el puntero de vacío. Así que hago una conversión de tipo mediante conversión:

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

También probé reinterpret_cast pero no tuve suerte, aunque el operador de elenco de C parece funcionar.

La conversión de un void* a un puntero de función directamente no está permitida (no debe comstackrse utilizando ninguno de los moldes) en C ++ 98/03. Es soportado condicionalmente 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. Un void* , como lo define el C ++ 98/03 estándar, estaba destinado a apuntar a objetos y no a contener punteros de función o punteros de miembro.

Sabiendo que lo que está haciendo depende en gran medida de la implementación, aquí hay una opción que debe comstackr y trabajar (asumiendo punteros de 32 bits, use long long para 64 bit) en la mayoría de las plataformas, aunque es un comportamiento claramente indefinido según la norma:

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

Y aquí hay otra opción que debe comstackr y trabajar, pero conlleva las mismas advertencias que la anterior:

 fptr my_ptr = 0; *reinterpret_cast(&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(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; 

Básicamente explota el hecho de que la dirección del puntero a la función es un puntero a objeto [void (*(*object_ptr))()] – así que 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 debería hacer lo que espera que haga en la mayoría de las implementaciones.

Tenga en cuenta que C ++ 11 permite dicha conversión y desde gcc 4.9 y superior esta conversión no genera una advertencia: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57869 .

Ver discusiones SO:

  • Cambia entre puntero a función y puntero a objeto en C y C ++
  • ¿Por qué los punteros a las funciones y los punteros de datos son incompatibles en C / C ++?
  • puede anular * ser utilizado para almacenar indicadores de función?
  • Usando reinterpret_cast para convertir una función en void *, ¿por qué no es ilegal?

Esto se comstack en Visual Studio sin usar el reinterpret cast:

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

Encontré esta solución (un poco fea). 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; } 

Uno podría usar la siguiente técnica:

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

O

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

Comstackdo con:

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

Esto puede ayudarte. Imprime “Hola”.

 #include  void hello() { std::cout << "Hello" << std::endl; } int main() { typedef void (*fptr)(); fptr gptr = (fptr) (void *) &hello; gptr(); } 

O puedes hacer:

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

donde & hello es reemplazado por el comando dlsym.