void* 到指针

发布于 2024-11-09 01:21:32 字数 1926 浏览 0 评论 0原文

通常,当调用动态加载的函数时,我通常会执行标准的直接转换:

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

我的问题:

  1. void*(注意:不是void**)对对象指针类型的行为定义良好吗?
  2. 为什么编译器允许在 void** 上使用 static_cast
  3. 为什么我蠢到去尝试这个?
  4. 你还发现这个例子还有什么问题吗?

由于代码清晰(并且因为我知道它应该有效),我决定再次使用方法#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:

  1. Is the behavior of a void* (note: not a void**) to an object pointer type well-defined?
  2. Why does the compiler allow static_cast<void*> on a void**?
  3. Why am I stupid enough to try this?
  4. 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

后eg是否自 2024-11-16 01:21:32
typedef int (*GenericFn)(); // matches x86 FARPROC, minus explicit calling convention
typedef bool (*DesiredFn)(int,int);

DesiredFn target = nullptr;

void* temp = static_cast<void*>(&target); // pointer to function pointer

这里没有什么问题,但是演员阵容是不必要的。指向任何对象的指针(指向函数的指针也是对象)无需强制转换即可转换为指向 void 的指针。例如,

void* temp = ⌖

GenericFn* address = static_cast<GenericFn*>(temp);

您可以从指向 void 的指针转换为指向任何对象类型的指针,但只有当您将转换为 void* 的值强制转换回它所转换的原始类型。从技术上讲,只有 static_cast(temp) 才会有明确定义的结果。

*address = GetProcAddress(module, "MyFunction"); // supposedly valid?

这在技术上是不正确的,因为您对分配给 address 的值的类型撒了谎,因此 address 没有指向与其类型信息匹配的对象。

话虽如此,在许多实现中,函数指针都以相同的方式表示,并且任何强制转换和转换都不会对实际存储的值产生任何影响。只要您通过与指针类型实际匹配的指针调用该函数,就不会有任何问题。

毕竟,您必须依赖于 reinterpret_castGetProcAddress 的实现行为才能使原始方法正常工作,但是 - 正如您所说 - 我建议坚持使用在这种情况下采用 reinterpret_cast 方法,因为它更清楚发生了什么。

typedef int (*GenericFn)(); // matches x86 FARPROC, minus explicit calling convention
typedef bool (*DesiredFn)(int,int);

DesiredFn target = nullptr;

void* temp = static_cast<void*>(&target); // pointer to function pointer

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.

void* temp = ⌖

GenericFn* address = static_cast<GenericFn*>(temp);

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 a void* back to the original type that it was converted from. Technically, only a static_cast<DesiredFn*>(temp) would have a well defined result.

*address = GetProcAddress(module, "MyFunction"); // supposedly valid?

This isn't technically correct as you have lied about the type of the value that you assigned to address so address 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 and GetProcAddress for the original method to work at all, but - as you say - I would recommend sticking with the reinterpret_cast approach in this case as it is clearer what is going on.

遇见了你 2024-11-16 01:21:32

这并不重要,因为 void* 和 void** 的大小相同。你只是改变类型。为什么不直接转换为你想要的类型呢?

DesiredFn target = 
    reinterpret_cast<DesiredFn>(GetProcAddress(module, "MyFunction"));

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?

DesiredFn target = 
    reinterpret_cast<DesiredFn>(GetProcAddress(module, "MyFunction"));
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文