Function pointers casting in C++

為{幸葍}努か 提交于 2019-11-26 08:10:47

问题


I have a void pointer returned by dlsym(), I want to call the function pointed by the void pointer. So I do a type conversion by casting:

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

I have also tried reinterpret_cast but no luck, although the C cast operator seems to work..


回答1:


Converting a void* to a function pointer directly is not allowed (should not compile using any of the casts) in C++98/03. It is conditionally supported in C++0x (an implementation may choose to define the behavior and if it does define it, then it must do what the standard says it should do. A void*, as defined by the C++98/03 standard, was meant to point to objects and not to contain function pointers or member pointers.

Knowing that what you are doing is heavily implementation dependent, here is one option that should compile and work (assuming 32 bit pointers, use long long for 64 bit) on most platforms, even though it is clearly undefined behavior according to the standard:

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

And here is another option that should compile and work, but carries the same caveats with it as the above:

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

Or, in Slow motion...

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

It essentially exploits the fact that the address of the function pointer is an object pointer (void (**object_ptr)()) - so we can use reinterpret_cast to convert it to any other object pointer: such as void**. We can then follow the address back (by dereferencing the void**) to the actual function pointer and store the value of the gptr there.

yuk - by no means well-defined code - but it should do what you expect it to do on most implementations.




回答2:


Note that C++11 allows such a conversion and from gcc 4.9 and above this conversion does not generate a warning: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57869.

See SO discussions:

  • Casts between pointer-to-function and pointer-to-object in C and C++
  • Why are function pointers and data pointers incompatible in C/C++?
  • can void* be used to store function pointers?
  • Using reinterpret_cast to cast a function to void*, why isn't it illegal?



回答3:


I found this (a bit ugly) solution. gcc with maximum warning level does not complain. This example calls dlsym() (that returns a void*) and returns the result in a function pointer.

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



回答4:


This compiles in Visual Studio without using reinterpret cast:

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



回答5:


One might use the following technique:

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

Or

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

Compiled with:

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



回答6:


You can cast dlsym to a function that returns the required pointer and then call it like this:

typedef void (*fptr)();
fptr my_fptr = reinterpret_cast<fptr (*)(void*, const char*)>(dlsym)(RTLD_DEFAULT, name);

PS. Casting a function pointer to a different function pointer and then calling it is undefined behavior (see point 7 in https://en.cppreference.com/w/cpp/language/reinterpret_cast) so it is better to cast the result of dlsym to uintptr_t and then to the required type:

fptr my_fptr = reinterpret_cast<fptr>(reinterpret_cast<uintptr_t>(dlsym(RTLD_DEFAULT, name)));



回答7:


This may help you. It prints "Hello".

#include <iostream>

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

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

OR you can do:

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

where &hello is replaced by the dlsym command.



来源:https://stackoverflow.com/questions/1096341/function-pointers-casting-in-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!