正确的方法来投射指针types
考虑下面的代码 (以及VirtualAlloc()
返回一个void*
)的事实:
BYTE* pbNext = reinterpret_cast<BYTE*>( VirtualAlloc(NULL, cbAlloc, MEM_COMMIT, PAGE_READWRITE));
为什么selectreinterpret_cast
而不是static_cast
?
我曾经认为reinterpret_cast
是好的例如铸造指针和整数types的指针(如DWORD_PTR
),但从一个void*
转换为BYTE*
,是不是static_cast
好吗?
在这种特殊情况下是否存在任何(微妙的)差异,还是仅仅是有效的指针转换?
C ++标准是否对这种情况有偏好,build议一种方式而不是另一种?
对于指向基本types的指针来说,可以接受cast,所以static_cast
没问题。
在两种指针types之间转换时,指针中保存的特定存储器地址可能需要更改 。
这是两个演员不同的地方。 static_cast
会做适当的调整。 reinterpret_cast
将避免改变指针的存储值。
出于这个原因,除非你知道 reinterpret_cast
是需要的,否则在指针types之间static_cast
是一个很好的通用规则。
你应该static_cast
。 如果您要撤消隐式转换,请使用static_cast
。
然而,在这种特殊情况下,没有什么区别,因为你是从void*
转换而来的。 但通常,两个对象指针之间的reinterpret_cast
定义为(§5.2.10/ 7):
一个对象指针可以被明确地转换为一个不同types的对象指针。 如果
T1
和T2
都是标准的,当“指向T1
指针”types的prvaluev
被转换为types“指向cvT2
指针”时, 结果是static_cast<cv T2*>(static_cast<cv void*>(v))
T2的布局types和alignment要求并不比T1
更严格,或者任何一种types都是void
。 将“指向T1
指针”types的prvalue转换为types“指向T2
指针”(其中T1
和T2
是对象types,T2
的alignment要求不比T1
的alignment要求更严格)并返回到原始types,指针值。 任何其他这种指针转换的结果都是未知的。
强调我的。 因为你的T1
已经是void*
,所以在reinterpret_cast
中void*
什么也不做。 总的来说,这是不正确的, 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
实际上并不指向derived
,所以使用它是未定义的行为。)
在这里, reinterpret_cast
出现了一个不同的值,因为它经历了void*
。 这就是为什么你应该尽可能使用static_cast
,而在必要的时候应该使用reinterpret_cast
。
使用static_cast
来指向和从void*
指针保证保存地址。
reinterpret_cast
另一方面保证,如果您将指针从一种types转换为其他types,并返回到原始types,地址将被保留。
尽pipe在大多数实现中,使用其中任何一个都会看到相同的结果,但static_cast
应该是首选的。
而我用C++11
记得,使用reinterpret_cast
for void*
具有定义良好的行为。 在此之前,这种行为被禁止。
It is not permitted to use reinterpret_cast to convert between pointers to object type and pointers to void.
build议的决议案(2010年8月):
更改5.2.10 [expr.reinterpret.cast]第7段如下:
对象指针可以显式转换为不同types的对象指针。 如果T1和T2都是标准布局types(3.9 [basic.types] ),则将“指向T1的指针”的prvalue v转换为types“指向cv T2的指针”,结果为static_cast(static_cast(v) ),并且T2的alignment要求不比T1更严格,或者任何一种types都是无效的。
将“指向T1的指针”types的prvalue转换为types“指向T2的指针”(其中T1和T2是对象types,T2的alignment要求不比T1的alignment要求更严格)并返回到原始types,指针值。 任何其他这样的指针转换的结果是未指定的。
更多信息在这里 。
感谢Jesse Good提供的链接。