void *指针

时间:2011-05-21 14:18:53

标签: c++ pointers casting

通常在调用动态加载函数时,我通常会进行标准直接投射:

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*(注意: a void**)对于明确定义的对象指针类型的行为是什么?
  2. 为什么编译器允许static_cast<void*>上的void**
  3. 为什么我傻到试试这个?
  4. 你看到这个例子还有什么问题吗?
  5. 我已经决定再次使用方法#1,因为代码清晰(因为我知道它应该工作)。我仍然对方法#2工作原理感兴趣:)。


    如果你想知道(关于我的解释)

    今天我删除了几个公共接口中的<windows.h>个依赖项,而不是像我应该的那样重新声明FARPROC,我实验性地将我的FARPROC返回类型函数更改为接受{ {1}}输出参数(我知道,它可能应该是void*)。

    void**

2 个答案:

答案 0 :(得分:1)

无关紧要,因为void *和void **的大小相同。你只是改变了类型。为什么不直接投射到你想要的类型?

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

答案 1 :(得分:1)

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的指针而不需要强制转换。 e.g。

void* temp = &target;

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

您可以从指向void的指针转换为指向任何对象类型的指针,但只有在将转换为void*的值转换回原始类型时,才会定义结果从...转换而来。从技术上讲,只有static_cast<DesiredFn*>(temp)才能得到明确的结果。

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

这在技术上并不正确,因为您已经分配了分配给address的值的类型,因此address未指向与其类型信息匹配的对象。

说了这么多,在许多实现中,函数指针都以相同的方式表示,并且任何强制转换和转换都不会对实际存储的值产生任何影响。只要你通过一个实际匹配指针类型的指针来调用函数就不会有任何问题。

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