C++ 中的函数指针转换

问题描述 投票:0回答:9

我有一个dlsym()返回的void指针,我想调用void指针指向的函数。 所以我通过强制转换进行类型转换:

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

我也尝试过

reinterpret_cast
但没有运气,尽管Ccast运算符似乎有效..

c++ casting function-pointers
9个回答
65
投票
在 C++98/03 中,不允许将

void*

 直接
转换为函数指针(不应使用任何强制转换进行编译)。它在 C++0x 中有条件地支持(实现可以选择定义行为,如果确实定义了行为,那么它必须执行标准规定的操作。A void*,由 C++98 定义) /03 标准,旨在指向对象,而不包含函数指针或成员指针。
知道您正在做的事情很大程度上依赖于实现,这里有一个选项应该在大多数平台上编译和工作(假设 32 位指针,对于 64 位使用 
long long

),即使根据标准它显然是未定义的行为:

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

这是另一个应该可以编译和工作的选项,但带有与上面相同的警告:

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

或者,慢动作...

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

它本质上利用了函数指针的地址是对象指针(
void  (**object_ptr)()
)这一事实 - 因此我们可以使用

reinterpret_cast

将其转换为任何其他对象指针:例如
void**
。然后我们可以沿着地址返回(通过取消引用 
void**
)到实际的函数指针并将 gptr 的值存储在那里。
yuk - 绝不是定义明确的代码 - 但它应该在大多数实现上执行您期望的操作。

请注意,C++11 允许此类转换,并且从 gcc 4.9 及更高版本开始,此转换不会生成警告:

20
投票
.

参见SO讨论:

C 和 C++ 中函数指针和对象指针之间的转换
  • 为什么C/C++中函数指针和数据指针不兼容?
  • void*可以用来存储函数指针吗?
  • 使用reinterpret_cast将函数强制转换为void*,为什么不违法?
好吧,如果您知道参数列表是什么,那么对其进行 c 转换就非常简单。如上所述,它具有未定义的行为,但我一直在我自己的宠物项目事件处理程序中使用它,并且它似乎在 MSVC 上工作得很好。

2
投票
我可以将相同的

void*

转换为

_beginthread_proc_type

 以使用 
_beginthread()
 启动线程,这似乎也不会导致任何问题(尽管我真的不知道向函数发送参数的后果是什么不需要任何参数,或者不向需要参数的函数发送参数即可,这似乎至少在我有限的测试中调用了该函数/启动了线程):
void somefunction(){
    std::cout <<"hi"<<std::endl;
}

void* function = (void*)&somefunction;
((void(__cdecl*)(void))(function)) ();

_beginthread((_beginthread_proc_type)function, 0, NULL);

我知道社区对宏产生了仇恨,但我在事件处理程序中使用宏来调用该函数:
#define call_voidstar_function(fc)     ((void(__cdecl*)(void))(fc)) ()

这可以在 Visual Studio 中进行编译,无需使用重新解释转换:

1
投票
void *ptr; int (*func)(void) = (int(*)(void))ptr; int num = func();

我找到了这个(有点难看)的解决方案。
具有最高警告级别的 gcc 不会抱怨。
此示例调用 dlsym() (返回 void*)并在函数指针中返回结果。

1
投票
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
投票
转换为返回所需指针的函数,然后像这样调用它:

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

PS。将函数指针转换为不同的函数指针,然后调用它是未定义的行为(请参阅
https://en.cppreference.com/w/cpp/language/reinterpret_cast
中的第7点),因此最好转换以下结果

dlsymuintptr_t

,然后至所需类型:
fptr my_fptr = reinterpret_cast<fptr>(reinterpret_cast<uintptr_t>(dlsym(RTLD_DEFAULT, name)));

可以使用以下技术:

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

或者

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

编译:

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

typeof 对我有用

0
投票
//fn_ptr = void_ptr; // error in C++, but works in C fn_ptr = (typeof(fn_ptr))(void_ptr);

令我惊讶的是 C++ 不会自动执行此操作...
#include <stdio.h>
//#include <cstdint> // uintptr_t

int fn(int x) {
  return x + 1;
}

int main() {

  void *void_ptr = (void*)&fn;

  typedef int (*fn_ptr_t)(int);

#ifndef __cplusplus
  // C
  fn_ptr_t fn_ptr = NULL;
#else
  // C++
  fn_ptr_t fn_ptr = nullptr;
#endif

#ifndef __cplusplus
  // C
  // this just works in C
  fn_ptr = void_ptr;
#else
  // C++
  // error: invalid conversion from ‘void*’ to ‘fn_ptr_t’ {aka ‘int (*)(int)’}
  //fn_ptr = void_ptr;

  // this works, but its verbose
  //fn_ptr = reinterpret_cast<fn_ptr_t>(reinterpret_cast<uintptr_t>(void_ptr));

  // cast with typeof. im surprised that C++ does not do this automatically
  fn_ptr = (typeof(fn_ptr))(void_ptr);
#endif

  // should return 2
  return fn_ptr(1);
}

这可能对你有帮助。它打印“你好”。 

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

或者你可以这样做:

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

其中 &hello 被 dlsym 命令替换。
    

© www.soinside.com 2019 - 2024. All rights reserved.