首页 > 解决方案 > c和c++中函数指针转换的区别

问题描述

我的代码在 c 和 c++ 中的行为不同。

void *(*funcPtr)() = dlsym(some symbol..) ; // (1) works in c but not c++

int (*funcPtr)();
*(void**)(&funcPtr) = dlsym(some symbol..) ; // (2) works in c++

我不明白第二次铸造如何在 c++ 中工作,而第一次铸造在 c++ 中不起作用。(1) show 的错误消息是 c++ 中从 void* 到 void*() 的无效转换。

标签: c++c

解决方案


问题是dlsym返回一个void*指针。虽然在 C 中,任何此类指针都可以隐式转换为任何其他(对象!)指针类型(为了比较:强制转换 malloc 的结果),但在 C++ 中并非如此(这里您需要强制转换 malloc的结果)。

但是,对于函数指针,即使在 C 中,这种强制转换也不是隐式的。显然,当您的代码编译时,您的编译器也为函数指针添加了这种隐式强制转换,作为编译器扩展(与对象指针一致);然而,为了完全符合标准,它实际上应该发出诊断信息,例如 C17 6.5.4.3 规定的编译器警告:

涉及指针的转换,除了 6.5.16.1 的约束允许的情况外,应通过显式转换来指定。

但现在,与其转换目标指针,不如将结果dlsym转换为适当的函数指针:

int (*funcPtr)() = reinterpret_cast<int(*)()>(dlsym(some symbol..));

或更简单:

auto funcPtr = reinterpret_cast<int(*)()>(dlsym(some symbol..));

甚至:

int (*funcPtr)() = reinterpret_cast<decltype(funcPtr)>(dlsym(some symbol..));

funcPtr(如果之前已经声明过,最后一个特别有趣。)

此外,您应该更喜欢 C++ 而不是 C 样式转换,请参阅上面的我的变体。您可以更精确地控制实际发生的类型转换。

旁注:您是否注意到问题中声明的两个函数指针的返回类型(void*vs. int)不同?此外,在 C 中不接受任何参数的函数需要声明为void f(void); 因此,函数指针:void*(*f)(void). C++ 允许使用voidfor 兼容性,而void在 C 中跳过具有完全不同的含义:该函数可以接受任何东西,您需要从其他地方(文档)知道实际上可以传递多少个类型的参数。


推荐阅读