通过 void* 进行铸造而不是使用reinterpret_cast [重复]

2024-04-16

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

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

代替:

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

但是,我找不到解释为什么这比直接演员更好。如果有人能给我解释或指出答案,我将非常感激。

提前致谢

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


对于允许进行此类强制转换的类型(例如,如果T1是 POD 类型并且T2 is unsigned char),该方法static_cast标准中有明确定义。

另一方面,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我相信它保证始终按照标准的预期工作:

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

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

3.9【基本类型】:

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

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

3.9.2[基本化合物]:

cv 限定 (3.9.3) 或 cv 不限定类型的对象void*(指向 void 的指针),可用于指向未知类型的对象。 Avoid*应能够保存任何对象指针。简历合格或简历不合格 (3.9.3)void*应具有与简历合格或简历不合格相同的表示和对齐要求char*.

3.10[基本.lval]:

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

  • ...
  • char 或 unsigned char 类型.

4.10[转换指针]:

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

5.2.9[expr.static.cast]:

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

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

9.2[类.mem]/17:

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

这似乎意味着reinterpret_cast指针之间以某种方式暗示“相同的地址”。去搞清楚。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

通过 void* 进行铸造而不是使用reinterpret_cast [重复] 的相关文章

随机推荐