是reinterpret_cast大部分没用吗?
我之前阅读过有关使用reinterpret_cast
的各种问题,并且我也阅读了C++标准中的相关措辞。本质上,归结为指针到指针 reinterpret_cast
操作的结果除了被强制转换回原始值之外,不能安全地用于任何指针类型。
然而,实际上,reinterpret_cast
的大多数实际使用似乎都基于一个(错误的)假设:reinterpret_cast
与 C 风格强制转换相同。例如,我见过很多代码使用 reinterpret_cast
从 char*
转换为 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
您无法以任何其他方式进行此类转换,因此您必须相信编译器对这种完全合理的转换所做的操作。
C 风格的强制转换将仅映射到
reinterpret_cast
,因此它将完全相同。在某些时候你必须相信你的编译器。该标准有一个限制,它只是简单地说“不。请阅读编译器手册”。当谈到交叉转换指针时,就是这样的一点。它允许您使用unsigned char
左值读取char
。无法将char*
转换为可用的unsigned char*
来执行此操作的编译器几乎不可用,因此不存在。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.
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 achar
using anunsigned char
lvalue. A compiler that cannot cast achar*
to a usableunsigned char*
to do such is just about unusable and doesn't exist for that reason.你是对的,标准被破坏了,但 N3242 试图修复这个问题:
reinterpret_cast
N3242, [expr.reinterpret.cast] 的值的定义:
这仍然没有定义什么;为了好玩,关于
static_cast
的不太相关的文本:“适当转换”
N3242,[class.mem]:
那是什么样的风格? “适当”?哈哈
,显然,这些人不知道如何编写规范。
这没有帮助。
标准坏了,坏了,坏了。
但每个人都明白它的真正含义。该标准的潜台词是:
这当然并不完美(但并不比标准的许多其他部分差),但我用了 200 万的时间编写了一个比委员会十年来编写的规范更好的规范。
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]:
This still defines nothing; for fun, the less irrelevant text about
static_cast
:"Suitably converted"
N3242, [class.mem]:
What kind of style is that? "suitably"? lol
Clearly, these guys don't know how to write a specification.
It doesn't help.
The standard is broken, broken, broken.
But everybody understands what it really means. The subtext of the standard says:
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.
标准中的其他地方有一些保证(请参阅有关类型表示的部分,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.
该标准指定了所有平台上必须发生的事情,您不必这样做。如果您将可移植性要求限制在您的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.
这听起来不对。假设 sizeof(void *) > sizeof(int *),
void *foo; reinterpret_cast(reinterpret_cast(foo))
可能会留下一个截断的指针值。实际上,
reinterpret_cast
不就是等同于 C 的默认强制转换吗?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?