开发者

void* to pointer

开发者 https://www.devze.com 2023-03-07 06:02 出处:网络
Normally when calling a dynamically loaded function I usually do a standard straight cast: typedef int (*GenericFn)(); // matches x86 FARPROC, minus explicit calling convention

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 = re开发者_高级运维interpret_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));
    }
};


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 = &target;

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.


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"));
0

精彩评论

暂无评论...
验证码 换一张
取 消