我有一个由dlsym()返回的void指针,我想调用由该指针指向的函数。 因此,我通过强制类型转换进行了类型转换:
void *gptr = dlsym(some symbol..) ;
typedef void (*fptr)();
fptr my_fptr = static_cast<fptr>(gptr) ;
我也尝试过 reinterpret_cast
,但没有成功,尽管 C 语言风格的强制类型转换符似乎可以工作。
我有一个由dlsym()返回的void指针,我想调用由该指针指向的函数。 因此,我通过强制类型转换进行了类型转换:
void *gptr = dlsym(some symbol..) ;
typedef void (*fptr)();
fptr my_fptr = static_cast<fptr>(gptr) ;
我也尝试过 reinterpret_cast
,但没有成功,尽管 C 语言风格的强制类型转换符似乎可以工作。
在C++98/03标准下,直接将void*
转换为函数指针是不允许的(任何类型的强制转换都不应该编译)。按条件,在C++0x中支持它(实现可以选择定义行为,如果定义了行为,则必须执行标准规定的操作)。根据C++98/03标准,void*
应该指向对象而不是包含函数指针或成员指针。
明确这种依赖于具体实现的做法可能会有所帮助。以下代码应该能够在大多数平台上编译和工作(假设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- 这并不是严格定义的代码 - 但它应该在大多数实现中做你所期望的事情。
size_t
类型 - 在任何平台上通常足够大,可以容纳一个指针,尽管这也不能保证。最好还是在可用的情况下(C99、C++TR1、C++0x),使用 <stdint.h>
/<cstdint>
头文件和其中的 intptr_t
类型定义。 - Pavel Minaevdlsym
包装器,该包装器返回函数指针,并从C++中调用该包装器。 - user1203803注意,C++11允许这样的类型转换,并且从gcc 4.9版本开始,此转换不会产生警告:https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57869。
参见SO讨论:
如果您了解参数列表是什么,那么将其强制转换为C语言类型非常简单。如上所述,这样做会导致未定义的行为,但我在自己的宠物项目中使用它作为事件处理程序已经运行良好,似乎在MSVC上也没有任何问题。
我可以将同一个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)) ()
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;
}
这个在Visual Studio中编译时不需要使用reinterpret_cast:
void *ptr;
int (*func)(void) = (int(*)(void))ptr;
int num = func();
reinterpret_cast
吗?编译器会选择哪种转换方式? - Janusz Lenarint (*fn)(int);
*(void **)(&fn) = dlsym(lib1, "function");
int result = (*fn)(3);
或者
fn = (int (*)(int))dlsym(lib1, "function");
编译使用:
g++ -Wall -pedantic -std=c++11
dlsym
转换为返回所需指针的函数,然后像这样调用它: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点),因此最好将dlsym
的结果转换为uintptr_t
,然后再转换为所需的类型:
fptr my_fptr = reinterpret_cast<fptr>(reinterpret_cast<uintptr_t>(dlsym(RTLD_DEFAULT, name)));
#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 命令替换。
void *
指针。 - Daniel Earwicker