是reinterpret_cast大部分没用吗?

发布于 2024-10-18 06:49:33 字数 1081 浏览 6 评论 0原文

我之前阅读过有关使用reinterpret_cast的各种问题,并且我也阅读了C++标准中的相关措辞。本质上,归结为指针到指针 reinterpret_cast 操作的结果除了被强制转换回原始值之外,不能安全地用于任何指针类型。

然而,实际上,reinterpret_cast 的大多数实际使用似乎都基于一个(错误的)假设:reinterpret_cast 与 C 风格强制转换相同。例如,我见过很多代码使用 reinterpret_castchar* 转换为 unsigned char* 以进行字符集转换例程。这是完全无害的,但严格来说它是不可移植的 - 不能保证从 char*unsigned char*reinterpret_cast 不会崩溃当您尝试取消引用 unsigned char* 指针时,您的程序会发生这种情况。

根据标准,似乎唯一reinterpret_cast的其他真正用途具有任何真正的保证,就是从指针转换为整数,反之亦然。

然而,在很多情况下,我们想要(并且应该能够)在不同的指针类型之间安全地进行转换。例如:uint16_t* 到新的 C++0x char16_t*,或者任何指向与原始类型具有相同大小/对齐方式的基本数据类型的指针。然而,reinterpret_cast 并不能保证这会起作用。

问题:我们如何安全地在指向相同大小/对齐方式的基本数据类型的指针之间进行转换,例如 char* --> 无符号字符*?由于reinterpret_cast似乎并不能保证这实际上有效,所以C风格的强制转换是这里唯一安全的选择吗?

I've read various previous questions about the use of reinterpret_cast, and I've also read the relevant wording in the C++ standard. Essentially, what it comes down to is that the result of a pointer-to-pointer reinterpret_cast operation can't safely be used for anything other than being cast back to the original pointer type.

In practice, however, most real-world uses of reinterpret_cast seem to be based on the (wrong) assumption that a reinterpret_cast is the same as a C-style cast. For example, I've seen lots of code which uses reinterpret_cast to cast from char* to unsigned char* for the purpose of character set conversion routines. This is completely harmless, yet strictly speaking it's not portable - there's no guarantee that a reinterpret_cast from char* to unsigned char* won't crash your program when you try to dereference the unsigned char* pointer.

It's seems the only other real use of reinterpret_cast that has any real guarantees, according to the standard, is converting from pointer to integer, and vice-versa.

And yet there are many cases where we'd want (and should be able to) safely convert between different pointer types. For example: uint16_t* to the new C++0x char16_t*, or really any pointer to a basic data type that is the same size/alignment as the original type. Yet reinterpret_cast provides no guarantees this should work.

Question: How can we safely convert between pointers to basic data-types of the same size/alignment, such as char* --> unsigned char*? Since reinterpret_cast doesn't seem to guarantee this actually works, are C-style casts the only safe option here?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

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

发布评论

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

评论(5

若言繁花未落 2024-10-25 06:49:33

当您尝试取消引用 unsigned char* 指针时,不能保证从 char* 到 unsigned char* 的 reinterpret_cast 不会使您的程序崩溃。

您无法以任何其他方式进行此类转换,因此您必须相信编译器对这种完全合理的转换所做的操作。

由于reinterpret_cast似乎并不能保证这实际上有效,所以C风格的强制转换是这里唯一安全的选择吗?

C 风格的强制转换将仅映射到reinterpret_cast,因此它将完全相同。在某些时候你必须相信你的编译器。该标准有一个限制,它只是简单地说“不。请阅读编译器手册”。当谈到交叉转换指针时,就是这样的一点。它允许您使用 unsigned char 左值读取 char。无法将 char* 转换为可用的 unsigned char* 来执行此操作的编译器几乎不可用,因此不存在。

there's no guarantee that a reinterpret_cast from char* to unsigned char* won't crash your program when you try to dereference the unsigned char* pointer.

You can't do such a cast in any other way, so you have to have to trust what your compiler does with this completely reasonable cast.

Since reinterpret_cast doesn't seem to guarantee this actually works, are C-style casts the only safe option here?

The C-style cast will just map to reinterpret_cast so it will be exactly the same. At some point you have to trust your compiler. The Standard has a limit on which it simply says "no. read your compiler's manual". When it comes to cross-casting pointers, this is such a point. It allows you to read a char using an unsigned char lvalue. A compiler that cannot cast a char* to a usable unsigned char* to do such is just about unusable and doesn't exist for that reason.

对不⑦ 2024-10-25 06:49:33

本质上,它归结为指针到指针reinterpret_cast操作的结果除了被强制转换回原始指针类型之外不能安全地用于任何其他用途。< /p>

你是对的,标准被破坏了,但 N3242 试图修复这个问题:

reinterpret_cast

N3242, [expr.reinterpret.cast] 的值的定义:

当“指向 T1 的指针”类型的纯右值 v 转换为“指向 cv T2 的指针”类型时,结果为 static_cast(static_cast(v) )如果T1和T2都是标准布局类型(3.9)并且T2的对齐要求不比T1严格。

这仍然没有定义什么;为了好玩,关于 static_cast 的不太相关的文本:

“指向 cv1 void 的指针”类型的纯右值可以转换为“指向 cv2 T 的指针”类型的纯右值,其中 T 是对象类型,而 cv2 与 cv 限定相同或大于 cv 限定,CV1。空指针值将转换为目标类型的空指针值。指向对象的指针类型值转换为“指向 cv void 的指针”并返回(可能具有不同的 cv 限定)应具有其原始值。

“适当转换”

N3242,[class.mem]:

指向标准布局结构对象的指针,适当使用reinterpret_cast转换,指向其初始成员(或者如果该成员是位字段,则到它所在的单位),反之亦然。

那是什么样的风格? “适当”?哈哈

,显然,这些人不知道如何编写规范。

C 风格转换是这里唯一安全的选择吗?

这没有帮助。

标准坏了,坏了,坏了。

但每个人都明白它的真正含义。该标准的潜台词是:

当“指向 T1 的指针”类型的纯右值 v 转换为“指向 cv T2 的指针”类型时,结果 static_cast(static_cast(v))如果 T1 和 T2 都是标准布局类型 (3.9) 并且 T2 的对齐要求不比 T1 更严格,则指向 v 的内存地址。

这当然并不完美(但并不比标准的许多其他部分差),但我用了 200 万的时间编写了一个比委员会十年来编写的规范更好的规范。

Essentially, what it comes down to is that the result of a pointer-to-pointer reinterpret_cast operation can't safely be used for anything other than being cast back to the original pointer type.

You are right, the standard was broken, but N3242 tries to fix that:

Definition of the value of reinterpret_cast<T*>

N3242, [expr.reinterpret.cast]:

When a prvalue v of type “pointer to T1” is converted to the type “pointer to cv T2”, the result is static_cast<cv T2*>(static_cast<cv void*>(v)) if both T1 and T2 are standard-layout types (3.9) and the alignment requirements of T2 are no stricter than those of T1.

This still defines nothing; for fun, the less irrelevant text about 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. The null pointer value is converted to the null pointer value of the destination type. A value of type pointer to object converted to “pointer to cv void” and back, possibly with different cv-qualification, shall have its original value.

"Suitably converted"

N3242, [class.mem]:

A pointer to a standard-layout struct object, suitably converted using a reinterpret_cast, points to its initial member (or if that member is a bit-field, then to the unit in which it resides) and vice versa.

What kind of style is that? "suitably"? lol

Clearly, these guys don't know how to write a specification.

C-style casts the only safe option here?

It doesn't help.

The standard is broken, broken, broken.

But everybody understands what it really means. The subtext of the standard says:

When a prvalue v of type “pointer to T1” is converted to the type “pointer to cv T2”, the result is static_cast<cv T2*>(static_cast<cv void*>(v))points to the memory address as v if both T1 and T2 are standard-layout types (3.9) and the alignment requirements of T2 are no stricter than those of T1.

That's certainly not perfect (but not worse than many others parts of the standard), but in 2 mn I wrote a better spec than the committee did in a decade.

平安喜乐 2024-10-25 06:49:33

标准中的其他地方有一些保证(请参阅有关类型表示的部分,IIRC,要求相应的无符号和有符号类型共享公共值的表示,仍然 IIRC,还有一些文本保证您可以将任何内容读取为字符)。但还要注意,有些地方甚至会减少您正在阅读的部分(其中指出事物是实现定义的和未指定的):某些形式的类型双关是未定义的行为。

There are some guarantees elsewhere in the standard (see the section on type representation which, IIRC, mandates that corresponding unsigned and signed types share the representation for the common values, still IIRC, there is also some text guaranteeing that you can read anything as characters). But note also that there are some places which lessen even the section you are reading (which states that things are implementation defined and unspecified): some forms of type punning are undefined behavior.

剩一世无双 2024-10-25 06:49:33

该标准指定了所有平台上必须发生的事情,您不必这样做。如果您将可移植性要求限制在您的reinterpret_cast实际工作的平台上,那很好。

在实际支持 uint16_t 的平台上,转换可能会起作用。在 char16_t 为 18、24、32 或 36 位宽的平台上,它可能不会做正确的事情。问题是,你必须支持这样的平台吗?语言标准想要。

The standard specifies what has to happen on all platforms, you don't have to do that. If you limit your portability requirements to platforms where your reinterpret_cast actually works, that's fine.

On platforms that actually support a uint16_t, the cast is likely to work. On platforms where char16_t is 18, 24, 32, or 36 bits wide, it might not do the right thing. The question is, do you have to support such platforms? The language standard wants to.

你的笑 2024-10-25 06:49:33

指针到指针的reinterpret_cast操作的结果除了被强制转换回原始指针类型之外不能安全地用于任何其他用途。

这听起来不对。假设 sizeof(void *) > sizeof(int *),void *foo; reinterpret_cast(reinterpret_cast(foo)) 可能会留下一个截断的指针值。

实际上,reinterpret_cast 不就是等同于 C 的默认强制转换吗?

the result of a pointer-to-pointer reinterpret_cast operation can't safely be used for anything other than being cast back to the original pointer type.

That does not sound right. Assuming sizeof(void *) > sizeof(int *), void *foo; reinterpret_cast<void *>(reinterpret_cast<int *>(foo)) could leave you with a truncated pointer value.

Is it not that reinterpret_cast is — in practice — simply the equivalent to C's default cast?

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