C++ 转换指针类型的正确方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15578935/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Proper way of casting pointer types
提问by Mr.C64
Considering the following code(and the fact that VirtualAlloc()
returns a void*
):
考虑以下代码(以及VirtualAlloc()
返回 avoid*
的事实):
BYTE* pbNext = reinterpret_cast<BYTE*>(
VirtualAlloc(NULL, cbAlloc, MEM_COMMIT, PAGE_READWRITE));
why is reinterpret_cast
chosen instead of static_cast
?
为什么reinterpret_cast
选择而不是static_cast
?
I used to think that reinterpret_cast
is OK for e.g. casting pointers to and from integer types (like e.g. DWORD_PTR
), but to cast from a void*
to a BYTE*
, isn't static_cast
OK?
我曾经认为这reinterpret_cast
可以用于例如将指针转换为整数类型(如 eg DWORD_PTR
),但是从 a 转换void*
为 a BYTE*
,不是static_cast
可以吗?
Are there any (subtle?) differences in this particular case, or are they just both valid pointer casts?
在这种特殊情况下是否有任何(微妙的?)差异,或者它们只是有效的指针转换?
Does the C++ standard have a preference for this case, suggesting a way instead of the other?
C++ 标准是否对这种情况有偏好,建议一种方法而不是另一种方法?
采纳答案by Drew Dormann
For convertible pointers to fundamental typesboth casts have the same meaning; so you are correct that static_cast
is okay.
对于指向基本类型的可转换指针,两种类型转换具有相同的含义;所以你是对的,static_cast
没关系。
When converting between some pointer types, it's possible that the specific memory address held in the pointer needs to change.
在某些指针类型之间进行转换时,可能需要更改指针中保存的特定内存地址。
That's where the two casts differ. static_cast
will make the appropriate adjustment. reinterpret_cast
will not.
这就是两个演员不同的地方。 static_cast
会做适当的调整。 reinterpret_cast
将不会。
For that reason, it's a good general rule to static_cast
between pointer types unless you knowthat reinterpret_cast
is desired.
出于这个原因,static_cast
在指针类型之间这是一个很好的一般规则,除非您知道这reinterpret_cast
是需要的。
回答by GManNickG
You should static_cast
. Use static_cast
in cases where you're undoing an implicit conversion.
你应该static_cast
。在您撤消隐式转换的情况下使用static_cast
。
In this particular case, however, there is no difference because you're converting from void*
. But in general, reinterpret_cast
ing between two object pointers is defined to be (§5.2.10/7):
但是,在这种特殊情况下,没有区别,因为您是从void*
. 但一般来说,reinterpret_cast
两个对象指针之间的 ing 定义为(第 5.2.10/7 节):
An object pointer can be explicitly converted to an object pointer of a di?erent type. When a prvalue
v
of type “pointer toT1
” is converted to the type “pointer to cvT2
”, the result isstatic_cast<cv T2*>(static_cast<cv void*>(v))
if bothT1
andT2
are standard-layout types and the alignment requirements ofT2
are no stricter than those ofT1
, or if either type isvoid
. Converting a prvalue of type “pointer toT1
” to the type “pointer toT2
” (whereT1
andT2
are object types and where the alignment requirements ofT2
are no stricter than those ofT1
) and back to its original type yields the original pointer value. The result of any other such pointer conversion is unspeci?ed.
对象指针可以显式转换为不同类型的对象指针。当
v
“pointer toT1
”类型的纯右值转换为“pointer to cvT2
”类型时,结果是static_cast<cv T2*>(static_cast<cv void*>(v))
如果T1
和T2
都是标准布局类型,并且 的对齐要求T2
不比 严格T1
,或者如果任一类型是void
。将“pointer toT1
”类型的纯右值转换为“pointer to ”类型T2
(其中T1
和T2
是对象类型,其中 的对齐要求T2
不比的对齐要求严格T1
)并返回其原始类型会产生原始指针值。任何其他此类指针转换的结果是未指定的。
Emphasis mine. Since T1
for you is already void*
, the cast to void*
in reinterpret_cast
does nothing. This is not true in general, which is what Drew Dormann is saying:
强调我的。因为T1
对于你来说已经是void*
,所以演员阵容到void*
inreinterpret_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);
}
Output:
输出:
00CBFD5B
00CBFD5B
00CBFD5C
00CBFD5B
00CBFD5B
00CBFD5C
(Note that because y
doesn't actually point to a derived
, using it is undefined behavior.)
(请注意,因为y
实际上并不指向 a derived
,所以使用它是未定义的行为。)
Here, reinterpret_cast
comes up with a different value because it goes through void*
. This is why you should use static_cast
when you can, and reinterpret_cast
when you have to.
在这里,reinterpret_cast
提出了一个不同的值,因为它通过void*
. 这就是为什么你应该static_cast
在可以和reinterpret_cast
必须的时候使用。
回答by Tuxdude
Using static_cast
to cast a pointer to and from void*
is guaranteed to preserve the address.
使用static_cast
来转换一个指针来void*
保证保留地址。
reinterpret_cast
on the other hand guarantees that if you cast the pointer from one type to other, and back to the original type, the address is preserved.
reinterpret_cast
另一方面保证,如果您将指针从一种类型转换为另一种类型,然后再转换回原始类型,则保留地址。
Although with most implementations, you would see the same results in using either of these, static_cast
should be preferred.
尽管对于大多数实现,您会在使用其中任何一个时看到相同的结果,但static_cast
应该首选。
And with C++11
I remember that, using reinterpret_cast
for void*
has a well defined behavior. Before that this behavior was prohibited.
并与C++11
我记得,使用reinterpret_cast
了void*
具有良好定义的行为。在此之前,这种行为是被禁止的。
It is not permitted to use reinterpret_cast to convert between pointers to object type and pointers to void.
Proposed resolution (August, 2010):
Change 5.2.10 [expr.reinterpret.cast] paragraph 7 as follows:
An object pointer can be explicitly converted to an object pointer of a different type. When a prvalue v of type “pointer to T1” is converted to the type “pointer to cv T2”, the result is static_cast(static_cast(v))if both T1 and T2 are standard-layout types (3.9 [basic.types]) and the alignment requirements of T2 are no stricter than those of T1, or if either type is void.
Converting a prvalue of type “pointer to T1” to the type “pointer to T2” (where T1 and T2 are object types and where the alignment requirements of T2 are no stricter than those of T1) and back to its original type yields the original pointer value. The result of any other such pointer conversion is unspecified.
提议的决议(2010 年 8 月):
将 5.2.10 [expr.reinterpret.cast] 第 7 段更改如下:
对象指针可以显式转换为不同类型的对象指针。当“指向 T1 的指针”类型的纯右值 v 转换为“指向 cv T2 的指针”类型时,如果 T1 和 T2 都是标准布局类型,则结果为static_cast(static_cast(v))(3.9 [basic.types] ) 并且 T2 的对齐要求并不比 T1 严格,或者如果任一类型为 void。
将“指向 T1 的指针”类型的纯右值转换为“指向 T2 的指针”类型(其中 T1 和 T2 是对象类型,并且 T2 的对齐要求不比 T1 的对齐要求严格)并返回其原始类型,生成原始类型指针值。任何其他此类指针转换的结果是未指定的。
More info here.
更多信息在这里。
Thanks to Jesse Goodfor the link.
感谢Jesse Good提供的链接。