reinterpret_cast无效是合法的*

Jon*_*Mee 8 c++ pointers void-pointers double-pointer reinterpret-cast

我正在查看https://en.cppreference.com/w/cpp/language/reinterpret_cast,我注意到它指定了我们可以始终转换为的合法类型:

  • byte*
  • char*
  • unsigned char*

但我并没有看到void*在列表中。这是疏忽吗?我的用例需要一个,reinterpret_cast因为我是从int**转换为void*。我最终会从void*后面投射到镜头上int**

Fra*_*eux 5

这些类型免于严格的别名规则。这并不意味着它们是您可以使用的唯一类型reinterpret_cast。如果将对象指针强制转换为另一种对象指针类型,则无法满足严格的别名规则的要求意味着您无法安全地取消引用结果。但是您仍然可以安全地将结果指针强制转换回原始类型,并将结果用作原始指针。

来自cppreference的相关部分reinterpret_cast

(任何对象指针类型T1*都可以转换为另一对象指针类型cv T2*。这完全等同于static_cast<cv T2*>(static_cast<cv void*>(expression))(这意味着,如果T2的对齐要求不严格于T1,则指针的值不会改变,并且结果指针的转换返回其原始类型会产生原始值。在任何情况下,只有在类型别名规则允许的情况下,才能安全地取消对结果指针的引用)

当铸造回原来的类型,AliasedType并且DynamicType是相同的,所以它们是相似的,这是由别名规则的地方是合法的非关联化的结果中列出的第一种情况reinterpret_cast

每当尝试DynamicType通过type 的glvalue 读取或修改类型的对象的存储值时,AliasedType除非满足以下条件之一,否则行为是不确定的:

  • AliasedTypeDynamicType相似。
  • AliasedType是的(可能具有简历资格)signed或的unsigned变体DynamicType
  • AliasedTypestd::byte,(从C ++ 17开始)charunsigned char:这允许将任何对象的对象表示形式检查为字节数组。


Ser*_*sta 2

从指向类型的指针转​​换为指向不同类型(包括 void )的指针始终是合法的,因此如果 T 是类型,则这是合法的 C++:

\n\n
T* x;\nvoid *y = reinterpret_cast<void *>(x);\n
Run Code Online (Sandbox Code Playgroud)\n\n

在现实世界中,它永远不会被使用,因为它void *是一种特殊情况,并且您可以通过以下方式获得相同的值static_cast

\n\n
void *y = static_cast<void *>(x); // equivalent to previous reinterpret_cast\n
Run Code Online (Sandbox Code Playgroud)\n\n

(事实上​​,上面的转换是隐式的,可以简单地编写void *y = x;- 感谢 Michael Kenzel 注意到它)

\n\n

为了更明确,该标准甚至在 C++17 8.2.10 Reinterpret 强制转换 [expr.reinterpret.cast], \xc2\xa77 的草案 n4659 中说

\n\n
\n

当对象指针类型的纯右值 v 转换为指向 cv T\xe2\x80\x9d 的对象指针类型 \xe2\x80\x9cpointer 时,结果为static_cast<cv T*>(static_cast<cv void*>(v))

\n
\n\n

当您提到 byte 和 char 是唯一的合法类型时,只是对这些类型取消引用转换后的指针是合法void不包含在这里,因为您永远无法取消引用void *.

\n\n
\n\n

具体回答你的问题

\n\n
\n

..我正在从 int** 转换为 void* 。我最终将从 void* 转换回 int**。

\n
\n\n

该标准保证第一个是标准(隐式读取)转换:

\n\n
\n

指向 cv T\xe2\x80\x9d 的 \xe2\x80\x9c 指针类型的纯右值(其中 T 是对象类型)可以转换为指向 cv void\xe2\x80 的 \xe2\x80\x9cpointer\n 类型的纯右值\x9d。此转换不会改变指针值 (6.9.2)。

\n
\n\n

所以这总是合法的:

\n\n
int **i = ...;\nvoid *v = i;\n
Run Code Online (Sandbox Code Playgroud)\n\n

对于背面铸造,标准规定(static_cast段落中):

\n\n
\n

指向 cv1 void\xe2\x80\x9d 的 \xe2\x80\x9c 指针类型的纯右值可以转换为指向 cv2 T\xe2\x80\x9d 的 \xe2\x80\x9c 指针类型的纯右值,

\n
\n\n

所以这也是合法的

\n\n
int **j = static_cast<int **>(v);\n
Run Code Online (Sandbox Code Playgroud)\n\n

并且该标准确保了j == i.

\n