reinterpret_cast to void *不使用函数指针

时间:2009-08-20 08:23:30

标签: c++ casting arm

我想重新解释将函数指针强制转换为void *变量。函数指针的类型将是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或其他类型   限定符

我在Casting a function pointer to another type

中阅读了解释

我担心以下解释。

  

在函数指针和。之间进行转换   常规指针(例如,将void (*)(void)投射到void*)。功能   指针不一定相同   大小为常规指针,因为   他们可能包含的一些架构   额外的上下文信息。这个   可能在x86上运行正常,但是   记住它是未定义的行为。

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

5 个答案:

答案 0 :(得分:7)

reinterpret_cast不能用于将函数指针强制转换为void*。虽然C cast可以做一些额外的事情,静态,重新解释和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 cast允许未经C ++强制转换组合授权的一种情况)

答案 1 :(得分:7)

reinterpret_cast只能用于

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

(参见标准第5.2.10节)

这尤其意味着从指向函数的指针转换为void *是不可能的,但您可以将其强制转换为void(*)()


编辑(2017):以上答案仅适用于C ++ 03。在C ++ 11到C ++ 17中,如果允许在函数指针和void *之间进行转换,则它是实现定义的。这通常是POSIX兼容系统的情况,因为dlsym()被声明为返回void *,并且客户端需要reinterpret_cast到正确的函数指针类型。

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

答案 2 :(得分: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的指针”的rvalue转换为“指向T2的指针”类型(其中T1和T2是函数类型)并返回其原始类型产生原始指针值之外,这种指针转换的结果未指定

答案 3 :(得分:3)

其他人指出你不能做那个演员(强烈地说,使用void*投射到reinterpret_cast也是不允许的 - 但是编译器默默地容忍。static_cast的目的是在这里使用)。

我通常会执行以下操作,即执行类型双关语,并且根据dlopen的联机帮助页(这是关于执行逆向转换来自 void* 一个函数指针)。获取函数指针的地址将为您提供数据指针:指向函数指针的指针。这样您就可以将其投射到void*。它假装它指向void*(而不是函数指针),然后读取它。

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

投放到void*的中间人使其等同于在内部使用两个static_cast,并使GCC对关于类型双关语的警告保持安静。使用C ++样式转换,这看起来像是两个static_cast

的组合
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强制转换,这看起来要复杂得多,因为您必须考虑const。 C风格的演员表会自动处理。玩得开心!

int main() {
    Test** pF(void **a);
    void *p = *static_cast<void* const*>(
      static_cast<void const*>(
        &static_cast<Test** (* const&)(void **a)>(&pF)));
}

答案 4 :(得分:0)

不应该Test* *p(void **a);Test* (*p)(void **a)

也许那是你的问题?