void* 到指针
通常,当调用动态加载的函数时,我通常会执行标准的直接转换:
typedef int (*GenericFn)(); // matches x86 FARPROC, minus explicit calling convention
typedef bool (*DesiredFn)(int,int);
GenericFn address = GetProcAddress(module, "MyFunction");
DesiredFn target = reinterpret_cast<DesiredFn>(address);
今天我做了一些不同的事情(而且很脑残)。
DesiredFn target = nullptr;
void* temp = static_cast<void*>(&target); // pointer to function pointer
GenericFn* address = static_cast<GenericFn*>(temp);
*address = GetProcAddress(module, "MyFunction"); // supposedly valid?
// temp is declared void* because a void** cannot be cast to GenericFn* without
// first doing a void** -> void* conversion
assert(target == MyFunction); // true on VC10, presumably GCC
我的问题:
void*
(注意:不是void**
)对对象指针类型的行为定义良好吗?- 为什么编译器允许在
void**
上使用static_cast
? - 为什么我蠢到去尝试这个?
- 你还发现这个例子还有什么问题吗?
由于代码清晰(并且因为我知道它应该有效),我决定再次使用方法#1。我仍然对为什么方法 #2 有效:) 感兴趣。
如果您想知道(关于我的解释)
今天我删除了几个公共接口中的
依赖项,而不是像我应该那样重新声明 FARPROC
,我实验性地更改了 FARPROC
返回类型函数,以接受 void*
输出参数(我知道,它可能应该是 void**)。
// implemented in some library cpp file
void detail::FunctionResolve(std::string export, void* output)
{
FARPROC* address = static_cast<FARPROC*>(output);
*address = GetProcAddress(...);
}
// header-defined interface class
template<typename F>
class RuntimeFunction {
F* target;
void SetFunction(std::string export) {
// old: this->target = reinterpret_cast<F*>(detail::FunctionResolve(...));
// new:
detail::FunctionResolve(export, static_cast<void*>(&this->target));
}
};
Normally when calling a dynamically loaded function I usually do a standard straight cast:
typedef int (*GenericFn)(); // matches x86 FARPROC, minus explicit calling convention
typedef bool (*DesiredFn)(int,int);
GenericFn address = GetProcAddress(module, "MyFunction");
DesiredFn target = reinterpret_cast<DesiredFn>(address);
Today I did something a little different (and braindead).
DesiredFn target = nullptr;
void* temp = static_cast<void*>(&target); // pointer to function pointer
GenericFn* address = static_cast<GenericFn*>(temp);
*address = GetProcAddress(module, "MyFunction"); // supposedly valid?
// temp is declared void* because a void** cannot be cast to GenericFn* without
// first doing a void** -> void* conversion
assert(target == MyFunction); // true on VC10, presumably GCC
My questions:
- Is the behavior of a
void*
(note: not avoid**
) to an object pointer type well-defined? - Why does the compiler allow
static_cast<void*>
on avoid**
? - Why am I stupid enough to try this?
- Do you see anything else that's wrong with this example?
I've since decided to use method #1 again because of code clarity (and because I know it's supposed to work). I'm still interested in why method #2 worked though :).
In case you're wondering (about my explanation)
Today I was removing <windows.h>
dependencies in several public interfaces, and rather than redeclare FARPROC
like I should have, I experimentally changed my FARPROC
return-type function to instead accept a void*
output parameter (I know, it should probably have been a void**
).
// implemented in some library cpp file
void detail::FunctionResolve(std::string export, void* output)
{
FARPROC* address = static_cast<FARPROC*>(output);
*address = GetProcAddress(...);
}
// header-defined interface class
template<typename F>
class RuntimeFunction {
F* target;
void SetFunction(std::string export) {
// old: this->target = reinterpret_cast<F*>(detail::FunctionResolve(...));
// new:
detail::FunctionResolve(export, static_cast<void*>(&this->target));
}
};
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这里没有什么问题,但是演员阵容是不必要的。指向任何对象的指针(指向函数的指针也是对象)无需强制转换即可转换为指向
void
的指针。例如,您可以从指向
void
的指针转换为指向任何对象类型的指针,但只有当您将转换为void*
的值强制转换回它所转换的原始类型。从技术上讲,只有static_cast(temp)
才会有明确定义的结果。这在技术上是不正确的,因为您对分配给
address
的值的类型撒了谎,因此address
没有指向与其类型信息匹配的对象。话虽如此,在许多实现中,函数指针都以相同的方式表示,并且任何强制转换和转换都不会对实际存储的值产生任何影响。只要您通过与指针类型实际匹配的指针调用该函数,就不会有任何问题。
毕竟,您必须依赖于
reinterpret_cast
和GetProcAddress
的实现行为才能使原始方法正常工作,但是 - 正如您所说 - 我建议坚持使用在这种情况下采用reinterpret_cast
方法,因为它更清楚发生了什么。There's nothing wrong here, but the cast is unnecessary. A pointer to any object (a pointer to a function is an object) can be converted to a pointer to
void
without a cast. e.g.You can convert from a pointer to
void
to a pointer to any object type but the results are only defined if you cast a value the was converted to avoid*
back to the original type that it was converted from. Technically, only astatic_cast<DesiredFn*>(temp)
would have a well defined result.This isn't technically correct as you have lied about the type of the value that you assigned to
address
soaddress
isn't pointing to an object that matches its type information.Having said all that, in many implementations function pointers are all represented in the same way and any cast and conversions don't have any effect on the value that is actually stored. So long as you call the function throught a pointer that actually matches the type of the pointer you won't have any problems.
After all, you have to rely on your implementation's behaviour of
reinterpret_cast
andGetProcAddress
for the original method to work at all, but - as you say - I would recommend sticking with thereinterpret_cast
approach in this case as it is clearer what is going on.这并不重要,因为 void* 和 void** 的大小相同。你只是改变类型。为什么不直接转换为你想要的类型呢?
It doesn't matter because void* and void** are the same size. You're just changing the type. Why not just cast directly to the type you want?