正确的投射指针类型的方法

时间:2013-03-22 20:01:46

标签: c++ pointers casting reinterpret-cast static-cast

考虑following code(以及VirtualAlloc() returns a void*)的事实:

BYTE* pbNext = reinterpret_cast<BYTE*>(
    VirtualAlloc(NULL, cbAlloc, MEM_COMMIT, PAGE_READWRITE));

为什么选择reinterpret_cast代替static_cast

我曾经认为reinterpret_cast可以用于,例如从整数类型(例如DWORD_PTR)转换指针,但要从void*转换为BYTE*,是不是static_cast好吗?

在这种特殊情况下是否有任何(微妙的?)差异,或者它们只是两个有效的指针转换?

C ++标准是否偏爱这种情况,建议采用一种方式而不是另一种方式?

3 个答案:

答案 0 :(得分:38)

对于可转换指针到基本类型,两个强制转换具有相同的含义;所以你是对的static_cast没问题。

在某些指针类型之间进行转换时,指针中保存的特定内存地址可能需要更改

这就是两个演员的不同之处。 static_cast将进行适当的调整。 reinterpret_cast不会。

因此,指针类型之间的static_cast是一个很好的一般规则,除非您知道需要reinterpret_cast

答案 1 :(得分:23)

你应该static_cast在您撤消隐式转化的情况下使用static_cast

但是,在这种特殊情况下,没有区别,因为您正在转换void*。但一般来说,两个对象指针之间的reinterpret_cast被定义为(§5.2.10/ 7):

  

可以将对象指针显式转换为不同类型的对象指针。当“指向v的指针”的prvalue T1转换为“指向cv T2的指针”时,结果为static_cast<cv T2*>(static_cast<cv void*>(v)) 如果T1T2都是标准布局类型,并且T2的对齐要求不比T1更严格,或者任何一种类型都是void 。将“指向T1”的类型的prvalue转换为“指向T2”的类型(其中T1T2是对象类型,{{T2的对齐要求1}}不比T1更严格,并且返回其原始类型会产生原始指针值。任何其他此类指针转换的结果都是未指定的。

强调我的。由于您的T1已经void*,因此void*reinterpret_cast的强制转换无效。通常情况并非如此,这就是Drew Dormann is saying

#include <iostream>

template <typename T>
void print_pointer(const volatile T* ptr)
{
    // this is needed by oversight in the standard
    std::cout << static_cast<void*>(const_cast<T*>(ptr)) << std::endl;
}

struct base_a {};
struct base_b {};
struct derived : base_a, base_b {};

int main()
{
    derived d;

    base_b* b = &d; // implicit cast

    // undo implicit cast with static_cast
    derived* x = static_cast<derived*>(b);

    // reinterpret the value with reinterpret_cast
    derived* y = reinterpret_cast<derived*>(b);

    print_pointer(&d);
    print_pointer(x);
    print_pointer(y);
}

输出:

  

00CBFD5B
  00CBFD5B
  00CBFD5C

(请注意,由于y实际上并未指向derived,因此使用它是未定义的行为。)

此处,reinterpret_cast会出现不同的值,因为它会通过void*。这就是您应该尽可能使用static_cast的原因,以及必要时使用reinterpret_cast

答案 2 :(得分:8)

使用static_cast转换指向void*的指针,保证保留地址。

另一方面,

reinterpret_cast保证如果将指针从一种类型转换为另一种类型,并返回原始类型,则保留地址。

虽然对于大多数实现,您会在使用其中任何一个时看到相同的结果,但{/ 1}}应该是首选。

对于static_cast我记得,C++11使用reinterpret_cast有明确定义的行为。在此之前,这种行为是被禁止的。

void*
  

提议的决议(2010年8月):

     

更改5.2.10 [expr.reinterpret.cast]第7段如下:

     

可以将对象指针显式转换为对象指针   不同的类型。当“指向T1的指针”类型的prvalue v是   转换为“指向cv T2的指针”类型,如果T1和T2都是标准布局,则结果为 static_cast(static_cast(v))   类型(3.9 [basic.types])和T2的对齐要求是否定的   比T1更严格,或者任何一种类型无效。

     

将“指针指向T1”类型的prvalue转换为“指向”的指针   T2“(其中T1和T2是对象类型和对齐的位置   T2的要求并不比T1的要求更严格并且回到它的要求   原始类型产生原始指针值。任何结果   其他此类指针转换未指定。

更多信息here

感谢Jesse Good获取链接。