64

考虑以下代码(以及VirtualAlloc()返回 avoid*的事实):

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

为什么reinterpret_cast选择而不是static_cast

我曾经认为这reinterpret_cast对于例如将指针转换为整数类型(如 eg DWORD_PTR)是可以的,但是从 avoid*转换为 a BYTE*,不是static_cast吗?

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

C++ 标准是否对这种情况有偏好,建议一种方式而不是另一种方式?

4

3 回答 3

53

对于指向基本类型的可转换指针,两种类型转换具有相同的含义;所以你是对的,static_cast没关系。

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

这就是两个演员不同的地方。 static_cast会做出适当的调整。 reinterpret_cast将不会。

static_cast出于这个原因,指针类型之间的通用规则是一个很好的通用规则,除非您知道reinterpret_cast是需要的。

于 2013-03-22T20:06:46.767 回答
30

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

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

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

强调我的。既然T1对你来说已经是void*,那么对void*in的强制转换reinterpret_cast什么也不做。这通常不是真的,这就是Drew Dormann 所说的

#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实际上并不指向 a derived,所以使用它是未定义的行为。)

在这里,reinterpret_cast提出了一个不同的值,因为它通过void*. 这就是为什么你应该static_cast在可以和reinterpret_cast必须的时候使用。

于 2013-03-22T20:18:46.120 回答
8

使用static_castto cast a pointer to and fromvoid*可以保证保留地址。

reinterpret_cast另一方面保证如果您将指针从一种类型转换为另一种类型,然后再转换回原始类型,则地址将被保留。

尽管在大多数实现中,使用其中任何一个都会看到相同的结果,但static_cast应该首选。

C++11记得,使用reinterpret_castforvoid*具有明确定义的行为。在此之前,这种行为是被禁止的。

It is not permitted to use reinterpret_cast to convert between pointers to object type and pointers to void.

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

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

对象指针可以显式转换为不同类型的对象指针。当“指向 T1 的指针”类型的纯右值 v 转换为“指向 cv T2 的指针”类型时,如果 T1 和 T2 都是标准布局类型(3.9 [basic.types ] ) 并且 T2 的对齐要求不比 T1 更严格,或者如果任一类型为 void。

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

更多信息在这里

感谢Jesse Good提供的链接。

于 2013-03-22T20:09:31.577 回答