功能指针分配工作在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)。

+0

...或者'static_cast':http://*.com/questions/310451/should-i-use-static-cast-or-reinterpret-cast-when-casting-a-void-to-不管 –

+2

C标准的版本我已经说过,指向'void'的指针可能会被转换为或指向任何_object_ type'(强调增加)。函数不是一个对象类型,并且C从未允许在'void *'和指向函数的指针之间进行转换(显式或隐式)。我不确定,但我认为诊断是必需的。 (我不认为它是未定义的行为。)而明确的演员(即使'reinterpret_cast')也不应该工作。 (大多数Unix编译器在这方面都不符合,但由于它是一个扩展,所以每个编译器都可以*地做它喜欢的事情。) –

+0

@JamesKanze是对的,C没有从'void *'到任何指针 - 功能类型。符合的C编译器必须发布诊断(可能只是一个警告);一个不合规的C编译器,大多数都是默认的,可以做任何它喜欢的事情。 –

因为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())); 
} 

(带多一点错误检查,当然)。

+0

据我所知,从'void *'到指向函数类型的显式转换(即强制转换)并不违反任何约束。但由于该标准没有定义这种转换的行为,因此其行为未定义。 POSIX可能确实定义了行为,因为它是免费的。 –

+0

谢谢@詹姆斯。我没有足够的智慧来评论编译器的缺陷。另外,你的第二行不能编译。除了错字'u'和'y'之外,显然还有一个右括号缺失,但我无法弄清楚应该去哪里。 –

+0

@KeithThompson我不确定C;在C++中,需要诊断。直到最近,Posix基本上都说使用我的第一个例子,上面;当我这次查看时,他们说要使用编译器扩展。所以我不知道(关于C)。在实践中,我总是使用类似于我的C++版本的东西,所以这个问题从来没有出现(另外,我从来没有见过一个强制执行这个规则的Unix编译器)。 –