考虑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 ++标准是否偏爱这种情况,建议采用一种方式而不是另一种方式?
答案 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
的指针”的prvalueT1
转换为“指向cvT2
的指针”时,结果为static_cast<cv T2*>(static_cast<cv void*>(v))
如果T1
和T2
都是标准布局类型,并且T2
的对齐要求不比T1
更严格,或者任何一种类型都是void
。将“指向T1
”的类型的prvalue转换为“指向T2
”的类型(其中T1
和T2
是对象类型,{{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获取链接。