考虑以下代码(以及
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
不好吗?
在这种特殊情况下是否有任何(微妙的?)差异,或者它们只是有效的指针转换?
C++ 标准是否对这种情况有偏好,建议一种方法而不是另一种方法?
对于基本类型的可转换指针,两种强制转换具有相同的含义;所以你是对的,
static_cast
没问题。
在某些指针类型之间进行转换时,指针中保存的特定内存地址可能需要更改。
这就是两个演员阵容的不同之处。
static_cast
会做出适当的调整。 reinterpret_cast
不会。
因此,指针类型之间的
static_cast
是一个很好的一般规则,除非您知道需要 reinterpret_cast
。
你应该
static_cast
。 如果要撤消隐式转换,请使用 static_cast
。
但是,在这种特殊情况下,没有区别,因为您是从
void*
转换的。但一般来说,两个对象指针之间的 reinterpret_cast
定义为 (§5.2.10/7):
对象指针可以显式转换为不同类型的对象指针。当“指向
”类型的纯右值v
转换为“指向 cvT1
”的指针时,如果T2
static_cast<cv T2*>(static_cast<cv void*>(v))
和T1
都是标准布局,则结果为T2
的类型和对齐要求并不比T2
更严格,或者如果任一类型是T1
。将“指向void
的指针”类型的纯右值转换为“指向T1
的指针”类型(其中T2
和T1
是对象类型,并且T2
的对齐要求并不比T2
更严格))并返回其原始类型,产生原始指针值。任何其他此类指针转换的结果均未指定。T1
强调我的。由于
T1
对您来说已经是 void*
,因此在 void*
中转换为 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
实际上并不指向 derived
,所以使用它是未定义的行为。)
在这里,
reinterpret_cast
会产生不同的值,因为它经过了void*
。这就是为什么您应该在可以时使用 static_cast
,在必须时使用 reinterpret_cast
。
使用
static_cast
与 void*
之间转换指针可以保证保留地址。
另一方面,reinterpret_cast
保证,如果将指针从一种类型转换为另一种类型,然后又转换回原始类型,则地址将被保留。
尽管在大多数实现中,使用其中任何一个都会看到相同的结果,但
static_cast
应该是首选。
对于
C++11
我记得,使用 reinterpret_cast
代表 void*
具有明确定义的行为。在此之前,这种行为是被禁止的。
不允许使用reinterpret_cast在指向对象类型的指针和指向void的指针之间进行转换。 ...
拟议决议(2010 年 8 月):
将 5.2.10 [expr.reinterpret.cast] 第 7 段更改如下:
对象指针可以显式转换为以下对象指针 不同的类型。当“指向 T1 的指针”类型的纯右值 v 为 转换为“指向 cv T2 的指针”类型,如果 T1 和 T2 都是标准布局,则结果为
types (3.9 [basic.types]) 和 T2 的对齐要求没有 比 T1 更严格,或者任一类型无效。static_cast<cv T2*>(static_cast<cv void*>(v))
将“指向 T1 的指针”类型的纯右值转换为“指向 T1 的指针”类型 T2”(其中 T1 和 T2 是对象类型,对齐方式 T2 的要求并不比 T1 严格) 并回到它的 原始类型产生原始指针值。任何结果 其他此类指针转换未指定。
更多信息请参阅 C++ 标准核心语言缺陷报告和已接受的问题,修订版 115,问题 #1120、
reinterpret_cast
和 void*
。
感谢Jesse Good提供链接。