本文介绍了通过 void* 进行转换,而不是使用 reinterpret_cast的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在读一本书,我发现不应该直接使用 reinterpret_cast,而是将转换为 void* 与 static_cast 结合使用:

I'm reading a book and I found that reinterpret_cast should not be used directly, but rather casting to void* in combination with static_cast:

T1 * p1=...
void *pv=p1;
T2 * p2= static_cast<T2*>(pv);

代替:

T1 * p1=...
T2 * p2= reinterpret_cast<T2*>(p1);

然而,我找不到解释为什么这比直接演员更好.如果有人能给我一个解释或指出我的答案,我将不胜感激.

However, I can't find an explanation why is this better than the direct cast. I would very appreciate if someone can give me an explanation or point me to the answer.

提前致谢

附言我知道 reinterpret_cast 用于什么,但我从未见过以这种方式使用

p.s. I know what is reinterpret_cast used for, but I never saw that is used in this way

推荐答案

对于允许此类转换的类型(例如,如果 T1 是 POD 类型且 T2unsigned char),使用 static_cast 的方法在标准中有明确定义.

For types for which such cast is permitted (e.g. if T1 is a POD-type and T2 is unsigned char), the approach with static_cast is well-defined by the Standard.

另一方面,reinterpret_cast 完全是实现定义的——你得到的唯一保证是你可以将指针类型转换为任何其他指针类型,然后返回,然后你会得到原始值;而且,您可以将指针类型转换为足够大的整数类型以保存指针值(这取决于实现,并且根本不需要存在),然后将其转换回来,您将获得原始值.

On the other hand, reinterpret_cast is entirely implementation-defined - the only guarantee that you get for it is that you can cast a pointer type to any other pointer type and then back, and you'll get the original value; and also, you can cast a pointer type to an integral type large enough to hold a pointer value (which varies depending on implementation, and needs not exist at all), and then cast it back, and you'll get the original value.

更具体地说,我将引用标准的相关部分,突出重要部分:

To be more specific, I'll just quote the relevant parts of the Standard, highlighting important parts:

5.2.10[expr.reinterpret.cast]:

5.2.10[expr.reinterpret.cast]:

reinterpret_cast 执行的映射是实现定义的.[注意:它可能会,也可能不会,产生与原始值不同的表示.] ...指向对象的指针可以显式转换为指向不同类型对象的指针.)除了转换类型的右值指向 T1 的指针"指向类型指向 T2 的指针"(其中 T1 和 T2 是对象类型,其中 T2 的对齐要求不比 T1 严格)并返回其原始类型产生原始指针值,这种指针转换的结果是不确定的.

就像这样:

struct pod_t { int x; };
pod_t pod;
char* p = reinterpret_cast<char*>(&pod);
memset(p, 0, sizeof pod);

实际上是未指定的.

解释为什么 static_cast 起作用有点棘手.这是上面重写的代码以使用 static_cast,我相信它可以保证始终按照标准的预期工作:

Explaining why static_cast works is a bit more tricky. Here's the above code rewritten to use static_cast which I believe is guaranteed to always work as intended by the Standard:

struct pod_t { int x; };
pod_t pod;
char* p = static_cast<char*>(static_cast<void*>(&pod));
memset(p, 0, sizeof pod);

再次,让我引用标准中的部分,这些部分共同使我得出结论,上述内容应该是可移植的:

Again, let me quote the sections of the Standard that, together, lead me to conclude that the above should be portable:

3.9[basic.types]:

3.9[basic.types]:

对于 POD 类型 T 的任何对象(除基类子对象外),无论该对象是否持有 T 类型的有效值,构成该对象的底层字节 (1.7) 都可以复制到字符或无符号字符.如果将 char 或 unsigned char 数组的内容复制回对象,则该对象随后将保持其原始值.

T 类型对象的对象表示是 T 类型对象占用的 N 个 unsigned char 对象 的序列,其中 N 等于 sizeof(T).

The object representation of an object of type T is the sequence of N unsigned char objects taken up by the object of type T, where N equals sizeof(T).

3.9.2[basic.compound]:

3.9.2[basic.compound]:

cv-qualified (3.9.3) 或 cv-unqualified 类型的对象 void*(指向 void 的指针),可用于指向未知类型的对象.void* 应该能够保存任何对象指针.cv-qualified 或 cv-unqualified (3.9.3) void* 应与 cv-qualified 或 cv-unqualified char* 具有相同的表示和对齐要求>.

3.10[basic.lval]:

3.10[basic.lval]:

如果程序尝试通过以下类型之一以外的左值访问对象的存储值,则行为未定义):

  • ...
  • 字符或无符号字符类型.

4.10[conv.ptr]:

4.10[conv.ptr]:

指向 cv T 的指针"类型的右值(其中 T 是对象类型)可以转换为指向 cv void 的指针"类型的右值.将指向 cv T 的指针"转换为指向 cv void 的指针"的结果指向类型 T 的对象所在的存储位置的开头,就好像该对象是类型 T 的最派生对象 (1.8)(即,不是基类子对象).

5.2.9[expr.static.cast]:

5.2.9[expr.static.cast]:

任何标准转换序列(第 4 条)的逆,除了左值到右值 (4.1)、数组到指针 (4.2)、函数到指针 (4.3) 和布尔 (4.12) 转换,可以使用 static_cast 显式执行.

另一方面,我们有这个宝石:

On the other hand, we have this gem:

9.2[class.mem]/17:

9.2[class.mem]/17:

指向 POD 结构对象的指针,使用 reinterpret_cast 进行适当转换,指向其初始成员(或者如果该成员是位域,则指向它所在的单元),反之亦然.[注意:POD 结构对象中可能因此有未命名的填充,但不是在其开头,这是实现适当对齐所必需的.]

这似乎暗示指针之间的 reinterpret_cast 以某种方式暗示相同的地址".去搞清楚.

which seems to imply that reinterpret_cast between pointers somehow implies "same address". Go figure.

这篇关于通过 void* 进行转换,而不是使用 reinterpret_cast的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-23 07:46