7

我想将函数指针重新解释为 void* 变量。函数指针的类型将是 type Class* (*)(void*)

下面是示例代码,

class Test
{
    int a;
};

int main()
{
    Test* *p(void **a);
    void *f=reinterpret_cast<void*>(p);     
}

上面的代码适用于 Visual Studio/x86 编译器。但是使用ARM编译器,它会产生编译错误。不知道为什么。

错误:#694:reinterpret_cast 不能抛弃 const 或其他类型限定符

我阅读了将函数指针转换为另一种类型中的解释

我担心下面的解释。

在函数指针和常规指针之间进行强制转换(例如将 a 强制转换void (*)(void)为 a void*)。函数指针不一定与常规指针大小相同,因为在某些架构上它们可能包含额外的上下文信息。这可能在 x86 上可以正常工作,但请记住这是未定义的行为。

如何void (*)(void*) -> void*有效地进行此类转换,以便至少在大多数编译器中编译几乎相同?

4

5 回答 5

8

reinterpret_cast不能用于将指向函数的指针转换为void*. 虽然 C 类型转换可以做的一些额外的事情是静态、重新解释和 const 类型转换的组合所不允许的,但这种转换不是其中之一。

在 C 中,演员表是允许的,但它的行为没有定义(即,即使往返也不能保证工作)。

一些 POSIX 函数需要转换才能非常有用。

我在这里玩过几个编译器:

  • none 阻止 C 转换,即使在最高一致性模式下也是如此。有些根据警告和一致性级别发出警告,而其他人则无论我尝试什么都没有发出警告。
  • reinterpret_cast 是一些编译器的错误,即使在更宽松的级别,而其他编译器在所有情况下都接受它而没有发出警告。

在 C++0X 的最后一个可用草案中,reinterpret_cast有条件地支持函数指针和对象指针之间的关系。

请注意,这是否有意义将更多地取决于目标而不是编译器:像 gcc 这样的可移植编译器将具有目标体系结构和可能的 ABI 强加的行为。

正如其他人所说,

Test* *p(void **a);

定义一个函数,而不是指向函数的指针。但是指向函数隐式转换的指针的函数是为 reinterpret_cast 的参数进行的,所以 reinterpret_cast 得到的是一个Test** (*p)(void** a).

感谢 Richard,这让我更深入地重新审视了这个问题(为了记录,我错误地认为指向函数的指针指向对象的指针是 C 强制转换允许 C++ 强制转换组合未授权的东西的一种情况)。

于 2009-08-20T08:39:51.117 回答
7

reinterpret_cast 只能用于

  • 添加常量
  • 将指针转换为足够大的整数类型以容纳并返回
  • 将指向函数的指针转换为指向不同类型函数的指针
  • 将指向对象的指针转换为指向不同类型对象的指针
  • 将指向成员函数的指针转换为指向不同类型成员函数的指针
  • 将指向成员对象的指针转换为指向不同类型成员对象的指针
  • andreinterpret_cast<T&>(x)等价于*reinterpret_cast<T*>(&x)(使用内置的&and *)只要可以使用上述规则进行第二次强制转换。

(见标准第 5.2.10 节)

这尤其意味着无法从指向函数的指针进行强制转换void *,但您可以将其强制转换为void(*)().


编辑(2017):上面的答案只对 C++03 是正确的。在 C++11 到 C++17 中,如果void *允许函数指针之间的转换,则由实现定义。这在 POSIX 兼容系统上通常是这种情况,因为dlsym()它被声明为 return void *,并且客户端期望reinterpret_cast它具有正确的函数指针类型。

有关允许的转换的完整列表,请参见cppreference.com

于 2009-08-20T10:40:15.803 回答
4

如果您只是想在列表中存储不同类型的函数指针,那么您可以转换为通用函数指针类型:

class Test {
  int a;
};

int main()
{
  Test* *p(void **a);
  void (*f)()=reinterpret_cast<void (*)()>(p);
}

通过reinterpret_cast(5.2.10/6) 可以做到这一点:

指向函数的指针可以显式转换为指向不同类型函数的指针。通过指向与函数定义中使用的类型不同的函数类型(8.3.5)的指针调用函数的效果是未定义的。除了将“指向 T1 的指针”类型的右值转换为“指向 T2 的指针”类型(其中 T1 和 T2 是函数类型)并返回其原始类型会产生原始指针值之外,这种指针转换的结果是未指定的.

于 2009-08-20T09:46:39.297 回答
3

其他人指出你不能这样做(强烈地说,也不允许void*使用任何东西进行强制转换 - 但编译器会默默地容忍。打算在这里使用)。reinterpret_caststatic_cast

我通常执行以下操作,这是一个双关语,并且是推荐的方法,根据手册页dlopen(这是关于做相反的 - 转换函数 指针)。获取函数指针的地址会给你一个数据指针:指向函数指针的指针。这将允许您将其转换为. 它假装它指向一个(而不是函数指针),然后读取它。void* void*void*

Test* (*pF)(void **a);
void *p = *(void**)(void*)&pF;

中间转换 tovoid*使其等同于static_cast在内部使用 two ,并使 GCC 对类型双关语的警告保持沉默。使用 C++ 样式转换,这看起来像是两个static_cast's的组合

void *p = *static_cast<void**>(static_cast<void*>(&pF));

我发现使用这种技术,当左右类型的大小不同时,GCC 会自动注意到,并在这种情况下发出警告。不用说,就像所有试图解决此限制的技术一样,这是未定义的行为。


如果您有一个函数,并且想要void*指向它,您可以在一行中完成所有操作,但这在语法上有点麻烦。这里是如何做到这一点的,但如果你有阅读问题,我不推荐它 - 但是你可以在宏中使用它

// using the function declaration you provided
Test** pF(void **a); 
void *p = *(void**)(void *) &(Test** (* const&)(void **a))&pF;

开始能够执行类型的技巧是将临时函数指针转换为对 const 的左值引用,您可以获取其地址,然后像上面一样继续。

使用显式 C++ 样式static_cast转换,这看起来要复杂得多,因为您必须考虑 constness。C 风格的演员自动处理了这个问题。玩得开心!

int main() {
    Test** pF(void **a);
    void *p = *static_cast<void* const*>(
      static_cast<void const*>(
        &static_cast<Test** (* const&)(void **a)>(&pF)));
}
于 2009-08-20T13:17:52.917 回答
0

Test* *p(void **a);应该Test* (*p)(void **a)吗?

也许那是你的问题?

于 2009-08-20T09:17:39.277 回答