当将 void* 转换为任何内容时,我应该使用 static_cast 还是 reinterpret_cast

发布于 2024-07-08 14:43:51 字数 120 浏览 11 评论 0原文

static_castreinterpret_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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

鸠书 2024-07-15 14:43:52

static_cast 更适合将 void* 转换为其他类型的指针。

当两种类型之间存在自然、直观的转换(但不一定保证在运行时有效)时,static_cast 是首选的强制转换。 例如,您可以使用static_cast 将基类指针转换为派生类指针,这种转换在某些情况下有意义,但只有在运行时才能验证。 同样,您可以使用static_castint转换为char,它定义良好,但执行时可能会导致精度损失。

另一方面,reinterpret_cast 是一个转换运算符,旨在执行根本上不安全或不可移植的转换。 例如,您可以使用 reinterpret_castvoid * 转换为 int,如果您的系统碰巧有 >sizeof (void*)sizeof (int)。 您还可以使用reinterpret_castfloat*转换为int*,反之亦然,这是特定于平台的,因为特定的表示floatint 不保证彼此有任何共同点。

简而言之,如果您发现自己进行的转换在逻辑上有意义,但在运行时不一定会成功,请避免 reinterpret_cast。 如果您预先了解转换将在运行时工作,并与编译器进行通信“我知道这可能行不通,但至少它有意义,而且我有理由相信它会在运行时正确地做正确的事情。” 然后,编译器可以检查相关类型之间的转换,如果不是这种情况,则报告编译时错误。 使用reinterpret_cast通过指针转换来完成此操作完全绕过了编译时安全检查。

在某些情况下,您可能希望使用 dynamic_cast 而不是 static_cast,但这些情况大多涉及类层次结构中的强制转换,并且(很少)直接涉及 无效*

至于规范更喜欢哪一个,都没有被过度提及为“正确的使用方式”(或者至少,我不记得其中之一是这样提到的。)但是,我认为规范希望你使用 static_cast 而不是 reinterpret_cast。 例如,当使用 C 风格转换时,如

A* ptr = (A*) myVoidPointer;

尝试的转换运算符的顺序总是尝试在 reinterpret_cast 之前使用 static_cast,这是您想要的行为因为 reinterpret_cast 不保证可移植。

The static_cast is more appropriate for converting a void* 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 use static_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 use static_cast to convert from an int to a char, 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 use reinterpret_cast to convert from a void * to an int, which will work correctly if your system happens to have sizeof (void*)sizeof (int). You can also use reinterpret_cast to convert a float* to an int* or vice-versa, which is platform-specific because the particular representations of floats and ints 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. Using reinterpret_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 a static_cast, but these mostly involve casts in a class hierarchy and (only rarely) directly concern void*.

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 over reinterpret_cast. For example, when using a C-style cast, as in

A* ptr = (A*) myVoidPointer;

The order of casting operators that's tried always tries to use a static_cast before a reinterpret_cast, which is the behavior you want since reinterpret_cast isn't guaranteed to be portable.

扬花落满肩 2024-07-15 14:43:52

这是一个很难回答的问题。 一方面,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.

悍妇囚夫 2024-07-15 14:43:52

您可能通过隐式转换获得了 void*,因此您应该使用 static_cast,因为它最接近隐式转换。

You likely obtained that void* with implicit conversion, so you should use static_cast because it is closest to the implicit conversion.

猛虎独行 2024-07-15 14:43:52

关于实现定义的映射存在混乱。 这就是映射。 实现可以按照自己喜欢的方式进行内部映射,但否则必须做出其他保证。 reinterpret_cast 的结果不能简单地任意指向实现所考虑的其他对象的位置 - 尽管外部表示可能有所不同。 (虽然转为整数再转回来都会有原来的值,具体情况,概述)。 从根本上来说,实现的重新解释的转换是否返回相同的“内存位置”是无关紧要的; 它返回的任何内容都映射到相同的“值”。 (顺便说一句,核心指南明确回答了使用reinterpret_cast (char* /unsigned char*/std::byte*) 查看原始对象表示是定义的行为。)

相关标准规则 void* 转换:

static_cast

“指向 cv1 void 的指针”类型的纯右值可以转换为“指向 cv2 T 的指针”类型的纯右值,其中 T 是
一个对象类型,并且 cv2 与 cv1 具有相同的 cv 限定,或者比 cv1 更高的 cv 限定。 如果原来的
指针值代表内存中某个字节的地址A,A不满足对齐要求
T,则结果指针值未指定。 否则,如果原始指针值指向
对象 a,并且有一个 T 类型的对象 b(忽略 cv 限定),它是指针可相互转换的 (6.8.3)
对于 a,结果是指向 b 的指针。 否则,指针值不会因转换而改变。
[示例3:
T* p1 = 新 T; const T* p2 = static_cast(static_cast(p1)); 布尔 b = p1 == p2; // b 的值为 true。
——示例结束]

reintrepret_cast

对象指针可以显式转换为不同类型的对象指针。68 当纯右值 v of
对象指针类型转换为对象指针类型“指向 cv T 的指针”,结果为 static_cast(static_cast(v))< /strong>


关键是最后一句。 出于本问题的 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:

A prvalue of type “pointer to cv1 void” can be converted to a prvalue of type “pointer to cv2 T”, where T is
an object type and cv2 is the same cv-qualification as, or greater cv-qualification than, cv1. If the original
pointer value represents the address A of a byte in memory and A does not satisfy the alignment requirement
of T, then the resulting pointer value is unspecified. Otherwise, if the original pointer value points to an
object a, and there is an object b of type T (ignoring cv-qualification) that is pointer-interconvertible (6.8.3)
with a, the result is a pointer to b. Otherwise, the pointer value is unchanged by the conversion.
[Example 3 :
T* p1 = new T; const T* p2 = static_cast<const T*>(static_cast<void*>(p1)); bool b = p1 == p2; // b will have the value true.
—end example]

reintrepret_cast:

An object pointer can be explicitly converted to an object pointer of a different type.68 When a prvalue v of
object pointer type is converted to the object pointer type “pointer to cv T”, the result is static_cast<cv T*>(static_cast<cv void*>(v))

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

去了角落 2024-07-15 14:43:52

使用 static_cast 与使用 reinterpret_cast 之间的转换与 void* 是相同的。 请参阅链接中的答案。 但通常 static_cast 是首选,因为它更窄并且通常(但不是在这种特定情况下)更安全的转换。

Casting to and from void* using static_cast and using reinterpret_cast is identical. See the answer at the link. But usually static_cast is preferred because it is more narrow and in general (but not in this specific case) more safe conversion.

耀眼的星火 2024-07-15 14:43:52

为此,请使用static_cast。 仅在极少数情况下,没有其他方法时才使用reinterpret_cast

Use static_cast for this. Only in the rarest of rare cases when there is no other way use reinterpret_cast.

惟欲睡 2024-07-15 14:43:52

我建议始终使用尽可能弱的演员阵容。

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 a float. 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 some reinterpret_pointer_cast, because it's weaker and nothing else is sufficient.

一页 2024-07-15 14:43:52

reinterpret_cast 将强制将 void* 转换为目标数据类型。 它不保证任何安全性,并且您的程序可能会崩溃,因为底层对象可以是任何东西。

例如,您可以将 myclass* 类型转换为 void*,然后使用 reinterpret_cast 将其转换为 yourclass*它可能有完全不同的布局。

所以它更好并推荐使用static_cast

reinterpret_cast will forcefully convert the void* 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* to void* and then use reinterpret_cast to convert it to yourclass* which may have a completely different layout.

So its better and recommended to use static_cast

焚却相思 2024-07-15 14:43:51

使用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 by reinterpret_cast is implementation-defined.” [5.2.10.3]

But in the particular case of casting from void* to T* 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), while static_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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文