我想重新解释将函数指针强制转换为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*
进行此类转换,以便至少在大多数编译器中编译几乎相同?
答案 0 :(得分:7)
reinterpret_cast
不能用于将函数指针强制转换为void*
。虽然C cast可以做一些额外的事情,静态,重新解释和const转换的组合不允许这种转换,但转换不是其中之一。
在C中,允许施法,但是没有定义行为(即使往返行程也不能保证工作)。
有些POSIX函数需要转换才能很有用。
我和我在这里的几个编译器一起玩过:
在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)
?
也许那是你的问题?