功能指针分配工作在C但不是C++
我需要在运行时在Mac OS X中动态链接到库函数。在Apple's example之后,我声明了一个函数指针并将其赋值为dlsym()的结果。以下示例成功编译为纯C(.c)文件。但我需要这在C++文件,如果我编译这个例子是一个C++文件(的.cpp),铛编译器告诉我功能指针分配工作在C但不是C++
无法初始化类型的变量“无效()(字符*)”与一个右值类型'void '
它为什么在普通的'C',我该如何解决这个问题?
#include <dlfcn.h>
void Test() {
// Load the library which defines myFunc
void* lib_handle = dlopen("myLib.dylib", RTLD_LOCAL|RTLD_LAZY);
// The following line is an error if compiled as C++
void (*myFunc)(char*) = dlsym(lib_handle, "myFunc");
myFunc("Hello");
dlclose(lib_handle) ;
}
dlsym
返回void*
。在POSIX中(但不是标准C,正如James所指出的那样),有一个从void*
到指针函数类型的隐式转换,所以myFunc
的赋值就可以工作。在C++中不存在隐式转换(因为它不是类型安全的),所以你需要告诉你真的加入了铸意味着它的编译器:
void (*myFunc)(char*) = (void(*)(char*))dlsym(lib_handle, "myFunc");
(或者你可以看中了reinterpret_cast
)。
因为C编译器坏了。在void*
和指向 函数的指针之间没有转换 (显式或隐式),既不在C也不在C++中。
Posix的增加了一个限制,以C,并要求void*
和 指向函数具有相同的尺寸和表示,所以 在于:
void (*myFunc)(char *);
*(void (**myFunc)(char*))(&myFunc) = dlsym(...);
将工作。
在C++中,您可能需要使用类似:
class GetFunctionHelper;
GetFunctionHelper getFunction(void* dlHandle, std::string const& functionName);
class GetFunctionHelper
{
void* fromSystem;
freind GetFunctionHelper getFunction(void* , std::string const&);
GetFunctionHelper(void* fromSystem) : fromSystem(fromSystem) {}
public:
template <typename Ptr> operator Ptr() const
{
return *reinterpret_cast<Ptr const*>(&fromSystem);
}
};
GetFunctionHelper
getFunction(void* dlHandle, std::string const& functionName)
{
return GetFunctionHelper(dlsym(dlHandle, functionName.c_str()));
}
(带多一点错误检查,当然)。
据我所知,从'void *'到指向函数类型的显式转换(即强制转换)并不违反任何约束。但由于该标准没有定义这种转换的行为,因此其行为未定义。 POSIX可能确实定义了行为,因为它是免费的。 –
谢谢@詹姆斯。我没有足够的智慧来评论编译器的缺陷。另外,你的第二行不能编译。除了错字'u'和'y'之外,显然还有一个右括号缺失,但我无法弄清楚应该去哪里。 –
@KeithThompson我不确定C;在C++中,需要诊断。直到最近,Posix基本上都说使用我的第一个例子,上面;当我这次查看时,他们说要使用编译器扩展。所以我不知道(关于C)。在实践中,我总是使用类似于我的C++版本的东西,所以这个问题从来没有出现(另外,我从来没有见过一个强制执行这个规则的Unix编译器)。 –
...或者'static_cast':http://*.com/questions/310451/should-i-use-static-cast-or-reinterpret-cast-when-casting-a-void-to-不管 –
C标准的版本我已经说过,指向'void'的指针可能会被转换为或指向任何_object_ type'(强调增加)。函数不是一个对象类型,并且C从未允许在'void *'和指向函数的指针之间进行转换(显式或隐式)。我不确定,但我认为诊断是必需的。 (我不认为它是未定义的行为。)而明确的演员(即使'reinterpret_cast')也不应该工作。 (大多数Unix编译器在这方面都不符合,但由于它是一个扩展,所以每个编译器都可以*地做它喜欢的事情。) –
@JamesKanze是对的,C没有从'void *'到任何指针 - 功能类型。符合的C编译器必须发布诊断(可能只是一个警告);一个不合规的C编译器,大多数都是默认的,可以做任何它喜欢的事情。 –