铸造指针类型的有道(Proper way of casting pointer types)

2019-07-22 18:47发布

考虑下面的代码 (和事实VirtualAlloc()返回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 OK?

有没有在这个特殊的情况下,任何(细微的?)的差异,或者他们只是两个有效的指针类型转换?

请问C ++标准有一个偏爱这种情况下,建议的方式,而不是其他?

Answer 1:

对于敞篷指向基本类型的石膏都具有相同的含义; 所以你是正确的, static_cast是好的。

当一些指针类型之间的转换, 它可能是在指针需要保持特定的内存地址改变

这就是两种不同的铸件。 static_cast会做出相应的调整。 reinterpret_cast不会。

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



Answer 2:

你应该static_cast使用static_cast在你解开的隐式转换的情况。

在这种特殊情况下,然而,没有任何区别,因为你是从转换void* 。 但在一般情况下, reinterpret_cast 2个对象指针之间荷兰国际集团被定义为(§5.2.10/ 7):

一个对象指针可以显式转换到二FF erent类型的对象的指针。 当prvalue v型“指针的T1 ”被转换为类型“指向cv T2 ”, 结果是static_cast<cv T2*>(static_cast<cv void*>(v))如果两个T1T2是标准-layout类型和的对准要求T2并不比那些更严格的T1 ,或者如果任一类型是void 。 转换类型的prvalue“指针T1 ”的类型“指针T2 ”(其中T1T2是对象类型,并且其中的对准要求T2并不比那些更严格的T1 ),并返回到其原始类型产生的原始指针值。 任何其它这样的指针转换的结果是unspeci音响编辑。

重点煤矿。 由于T1你已经是void* ,要转换成void*reinterpret_cast什么都不做。 这不是一般的真实,这正是德鲁杜曼是说 :

#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时候,你不得不这样做。



Answer 3:

使用static_cast的指针转换和从void*是保证存放地址。

reinterpret_cast ,另一方面保证,如果你从一种类型转换指针到其他,回到原来的类型,地址被保留。

虽然大部分的实现,你会看到在使用这两种相同的结果, static_cast应该是首选。

并与C++11我记得,使用reinterpret_castvoid*有一个明确的行为。 在此之前,这种行为是被禁止的。

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”的prvalue v是转换为类型“指向cv T2”,其结果是的static_cast(的static_cast(V))如果两个T1和T2是标准布局类型(3.9 [basic.types] )和T2的对准要求并不比T1的严格,或者如果任一类型是无效的。

转换类型的prvalue“指针T1”的类型“指针T2”(其​​中,T1和T2是对象类型,并且其中T2的对准要求并不比T1的更严格的),并返回到其原始类型产生的原始指针值。 任何其它这样的指针转换的结果是不确定的。

更多信息这里 。

感谢杰西良好的链接。



文章来源: Proper way of casting pointer types