当将 void* 转换为任何内容时,我应该使用 static_cast 还是 reinterpret_cast
static_cast
和 reinterpret_cast
似乎都可以很好地将 void*
转换为另一种指针类型。是否有充分的理由偏爱其中之一?
Both static_cast
and reinterpret_cast
seem to work fine for casting void*
to another pointer type. Is there a good reason to favor one over the other?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
使用
static_cast
:它是最窄的强制转换,准确描述了此处进行的转换。有一种误解认为使用
reinterpret_cast
会是更好的匹配,因为它意味着“完全忽略类型安全,只是从 A 强制转换为 B”。然而,这实际上并没有描述
reinterpret_cast
的效果。相反,reinterpret_cast 具有多种含义,所有这些含义都表明“reinterpret_cast 执行的映射是实现定义的”。 [5.2.10.3]但在从
void*
转换为T*
的特定情况下,映射是完全由标准明确定义的;即,将类型分配给无类型指针而不更改其地址。这就是更喜欢
static_cast
的原因。此外,可以说更重要的是,每次使用
reinterpret_cast
都是非常危险的,因为它将任何东西真正转换为其他任何东西(对于指针),而static_cast
则要危险得多限制性的,从而提供更好的保护水平。这已经使我避免了我不小心试图将一种指针类型强制转换为另一种指针类型的错误。Use
static_cast
: it is the narrowest cast that exactly describes what conversion is made here.There’s a misconception that using
reinterpret_cast
would be a better match because it means “completely ignore type safety and just cast from A to B”.However, this doesn’t actually describe the effect of a
reinterpret_cast
. Rather,reinterpret_cast
has a number of meanings, for all of which holds that “the mapping performed byreinterpret_cast
is implementation-defined.” [5.2.10.3]But in the particular case of casting from
void*
toT*
the mapping is completely well-defined by the standard; namely, to assign a type to a typeless pointer without changing its address.This is a reason to prefer
static_cast
.Additionally, and arguably more important, is the fact that every use of
reinterpret_cast
is downright dangerous because it converts anything to anything else really (for pointers), whilestatic_cast
is much more restrictive, thus providing a better level of protection. This has already saved me from bugs where I accidentally tried to coerce one pointer type into another.static_cast
更适合将void*
转换为其他类型的指针。当两种类型之间存在自然、直观的转换(但不一定保证在运行时有效)时,
static_cast
是首选的强制转换。例如,您可以使用static_cast
将基类指针转换为派生类指针,这种转换在某些情况下有意义,但只有在运行时才能验证。同样,您可以使用static_cast
将int
转换为char
,它定义良好,但执行时可能会导致精度损失。另一方面,reinterpret_cast 是一个转换运算符,旨在执行根本上不安全或不可移植的转换。例如,您可以使用
reinterpret_cast
将void *
转换为int
,如果您的系统碰巧有>sizeof (void*)
≤sizeof (int)
。您还可以使用reinterpret_cast
将float*
转换为int*
,反之亦然,这是特定于平台的,因为特定的表示float
和int
不保证彼此有任何共同点。简而言之,如果您发现自己进行的转换在逻辑上有意义,但在运行时不一定会成功,请避免
reinterpret_cast
。如果您预先了解转换将在运行时工作,并与编译器进行通信“我知道这可能行不通,但至少它有意义,而且我有理由相信它会在运行时正确地做正确的事情。”然后,编译器可以检查相关类型之间的转换,如果不是这种情况,则报告编译时错误。使用reinterpret_cast
通过指针转换来完成此操作完全绕过了编译时安全检查。在某些情况下,您可能希望使用
dynamic_cast
而不是static_cast
,但这些情况大多涉及类层次结构中的强制转换,并且(很少)直接涉及无效*
。至于规范更喜欢哪一个,都没有被过度提及为“正确的使用方式”(或者至少,我不记得其中之一是这样提到的。)但是,我认为规范希望你使用
static_cast
而不是reinterpret_cast
。例如,当使用 C 风格转换时,如尝试的转换运算符的顺序总是尝试在
reinterpret_cast
之前使用static_cast
,这是您想要的行为因为reinterpret_cast
不保证可移植。The
static_cast
is more appropriate for converting avoid*
to a pointer of some other type.static_cast
is the cast of choice when there is a natural, intuitive conversion between two types that isn't necessarily guaranteed to work at runtime. For example, you can usestatic_cast
to convert base class pointers to derived class pointers, which is a conversion that makes sense in some cases but can't be verified until runtime. Similarly, you can usestatic_cast
to convert from anint
to achar
, which is well-defined but may cause a loss of precision when executed.reinterpret_cast
, on the other hand, is a casting operator designed to do conversions that are fundamentally not safe or not portable. For example, you can usereinterpret_cast
to convert from avoid *
to anint
, which will work correctly if your system happens to havesizeof (void*)
≤sizeof (int)
. You can also usereinterpret_cast
to convert afloat*
to anint*
or vice-versa, which is platform-specific because the particular representations offloat
s andint
s aren't guaranteed to have anything in common with one another.In short, if you ever find yourself doing a conversion in which the cast is logically meaningful but might not necessarily succeed at runtime, avoid
reinterpret_cast
.static_cast
is a good choice if you have some advance knowledge that the cast is going to work at runtime, and communicates to the compiler "I know that this might not work, but at least it makes sense and I have a reason to believe it will correctly do the right thing at runtime." The compiler can then check that the cast is between related types, reporting a compile-time error if this isn't the case. Usingreinterpret_cast
to do this with pointer conversions completely bypasses the compile-time safety check.There are a few circumstances where you might want to use a
dynamic_cast
instead of astatic_cast
, but these mostly involve casts in a class hierarchy and (only rarely) directly concernvoid*
.As for which one is preferred by the spec, neither is overly mentioned as "the right one to use" (or at least, I don't remember one of them being mentioned this way.) However, I think the spec wants you to use
static_cast
overreinterpret_cast
. For example, when using a C-style cast, as inThe order of casting operators that's tried always tries to use a
static_cast
before areinterpret_cast
, which is the behavior you want sincereinterpret_cast
isn't guaranteed to be portable.这是一个很难回答的问题。一方面,Konrad 对 reinterpret_cast 的规范定义提出了很好的观点,尽管在实践中它可能做了同样的事情。另一方面,如果您在指针类型之间进行转换(例如,通过 char* 在内存中索引时相当常见),static_cast 将生成编译器错误,并且您将被迫无论如何都要使用reinterpret_cast。
在实践中,我使用reinterpret_cast,因为它更能描述强制转换操作的意图。您当然可以为不同的运算符指定仅重新解释的指针(这保证返回相同的地址),但标准中没有这样的运算符。
This is a tough question. On the one hand, Konrad makes an excellent point about the spec definition for reinterpret_cast, although in practice it probably does the same thing. On the other hand, if you're casting between pointer types (as is fairly common when indexing in memory via a char*, for example), static_cast will generate a compiler error and you'll be forced to use reinterpret_cast anyway.
In practice I use reinterpret_cast because it's more descriptive of the intent of the cast operation. You could certainly make a case for a different operator to designate pointer reinterprets only (which guaranteed the same address returned), but there isn't one in the standard.
您可能通过隐式转换获得了
void*
,因此您应该使用static_cast
,因为它最接近隐式转换。You likely obtained that
void*
with implicit conversion, so you should usestatic_cast
because it is closest to the implicit conversion.关于实现定义的映射存在混乱。这就是映射。实现可以按照自己喜欢的方式进行内部映射,但否则必须做出其他保证。 reinterpret_cast 的结果不能简单地任意指向实现所考虑的其他对象的位置 - 尽管外部表示可能有所不同。 (虽然转为整数再转回来都会有原来的值,具体情况,概述)。 从根本上来说,实现的重新解释的转换是否返回相同的“内存位置”是无关紧要的;它返回的任何内容都映射到相同的“值”。 (顺便说一句,核心指南明确回答了使用reinterpret_cast (char* /unsigned char*/std::byte*) 查看原始对象表示是定义的行为。)
相关标准规则 void* 转换:
static_cast:
reintrepret_cast:
关键是最后一句。出于本问题的 void* 转换的目的,(并假设对象类型满足对齐要求、cv 资格,并且是安全派生的指针):
reinterpret_cast T* from void*
相当于
来自 void* 的 static_cast T*
。但你绝对、绝对绝对绝对应该使用
static_cast
,因为关于reinterpret_cast的可怕民间传说和ISO标准的复杂性可能会导致你受到同行不必要的长篇大论。There's confusion about implementation defined mappings. That is about mappings. The implementation can internally map however it likes, but it must make other guarantees otherwise. A result of reinterpret_cast can't simply arbitrarily point to what the implementation would otherwise consider some other object's location -- though the outward representation may differ. (Though converting to integer and back will have original value, in specific circumstances, outlined). Fundamentally, it's irrelevant whether the implementation's reinterpreted cast returns the same "memory location"; whatever it returns is mapped to the same "value". (Incidentally, The core guidelines explicitly answer a case where using reinterpret_cast (char*/unsigned char*/std::byte*) to view raw object representation is defined behavior.)
Relevant standards rules the void* cast:
static_cast:
reintrepret_cast:
The key is the last sentence. For the purposes of this question's void* cast, (and assuming object types meet alignment requirements, cv qualifications, and are safefly-derived pointers):
reinterpret_cast T* from void*
is equivalent to
static_cast T* from void*
.But you should definitely, definitely absolutely definitely use
static_cast
for no other reason that the scary folklore about reinterpret_cast and convolutedness of the ISO standard may lead to get you needlessly harangued by peers.????https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Ru-pun
使用
static_cast
与使用reinterpret_cast
之间的转换与void*
是相同的。请参阅链接中的答案。但通常static_cast
是首选,因为它更窄并且通常(但不是在这种特定情况下)更安全的转换。Casting to and from
void*
usingstatic_cast
and usingreinterpret_cast
is identical. See the answer at the link. But usuallystatic_cast
is preferred because it is more narrow and in general (but not in this specific case) more safe conversion.为此,请使用
static_cast
。仅在极少数情况下,没有其他方法时才使用reinterpret_cast
。Use
static_cast
for this. Only in the rarest of rare cases when there is no other way usereinterpret_cast
.我建议始终使用尽可能弱的演员阵容。
reinterpret_cast
可用于将指针强制转换为float
。演员阵容破坏结构越多,使用它就越需要注意。对于
char*
,我会使用 c 风格的转换,直到我们有一些reinterpret_pointer_cast
,因为它较弱,而且没有其他方法足够了。I suggest using the weakest possible cast always.
reinterpret_cast
may be used to cast a pointer to afloat
. The more structure-breaking the cast is, the more attention using it requires.In case of
char*
, I'd use c-style cast, until we have somereinterpret_pointer_cast
, because it's weaker and nothing else is sufficient.reinterpret_cast
将强制将void*
转换为目标数据类型。它不保证任何安全性,并且您的程序可能会崩溃,因为底层对象可以是任何东西。例如,您可以将
myclass*
类型转换为void*
,然后使用reinterpret_cast
将其转换为yourclass*
它可能有完全不同的布局。所以它更好并推荐使用
static_cast
reinterpret_cast
will forcefully convert thevoid*
to the target data type. It doesn't guarantee any safety and your program might crash as the underlying object could be anything.For ex, you could typecast an
myclass*
tovoid*
and then usereinterpret_cast
to convert it toyourclass*
which may have a completely different layout.So its better and recommended to use
static_cast