reinterpret_cast 是否合法*

Is it Legal to reinterpret_cast to a void*

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

但我没有看到列表中的void*。这是疏忽吗?我的用例需要 reinterpret_cast,因为我要从 int** 转换为 void*。我最终会从 void* 转换回 int**.

[expr.reinterpret.cast]/7:

An object pointer can be explicitly converted to an object pointer of a different type.

[basic.compound]/3:

The type of a pointer to cv void or a pointer to an object type is called an object pointer type.

不过您不需要使用 reinterpret_cast。每个指向类型为 cv-unqualified 的对象指针类型都可以隐式转换为 void*,并且可以通过 static_cast.

完成逆转换

这些类型不受严格的别名规则约束。这并不意味着它们是您可以与 reinterpret_cast 一起使用的唯一类型。在将对象指针转换为另一种对象指针类型的情况下,不满足严格别名规则的要求意味着您无法安全地取消引用结果。但是您仍然可以安全地将结果指针转换回原始类型,并像使用原始指针一样使用结果。

reinterpret_cast 上 cppreference 的相关部分:

(Any object pointer type T1* can be converted to another object pointer type cv T2*. This is exactly equivalent to static_cast<cv T2*>(static_cast<cv void*>(expression)) (which implies that if T2's alignment requirement is not stricter than T1's, the value of the pointer does not change and conversion of the resulting pointer back to its original type yields the original value). In any case, the resulting pointer may only be dereferenced safely if allowed by the type aliasing rules)

转换回原始类型时,AliasedTypeDynamicType是相同的,所以它们是相似的,这是别名规则列出的第一个合法取消引用的情况reinterpret_cast 的结果:

Whenever an attempt is made to read or modify the stored value of an object of type DynamicType through a glvalue of type AliasedType, the behavior is undefined unless one of the following is true:

  • AliasedType and DynamicType are similar.
  • AliasedType is the (possibly cv-qualified) signed or unsigned variant of DynamicType.
  • AliasedType is std::byte, (since C++17)char, or unsigned char: this permits examination of the object representation of any object as an array of bytes.

从指向类型的指针转​​换为指向不同类型的指针总是合法的包括 void,所以如果 T 是一个类型,这是合法的 C++:

T* x;
void *y = reinterpret_cast<void *>(x);

在现实世界中从不使用它,因为 void * 是一种特殊情况,并且您获得与 static_cast 相同的值:

void *y = static_cast<void *>(x); // equivalent to previous reinterpret_cast

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

更明确地说,标准甚至在 n4659 草案中针对 C++17 8.2.10 Reinterpret cast [expr.reinterpret.cast]、§7

When a prvalue v of object pointer type is converted to the object pointer type “pointer to cv T”, the result is static_cast<cv T*>(static_cast<cv void*>(v)).

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


专门回答你的问题

.. I'm casting from an int** to a void*. And I will eventually cast from the void* back to an int**.

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

A prvalue of type “pointer to cv T”, where T is an object type, can be converted to a prvalue of type “pointer to cv void”. The pointer value (6.9.2) is unchanged by this conversion.

所以这总是合法的:

int **i = ...;
void *v = i;

对于背投,标准说(在static_cast段):

A prvalue of type “pointer to cv1 void” can be converted to a prvalue of type “pointer to cv2 T”,

所以这也是合法的

int **j = static_cast<int **>(v);

并且标准确保 j == i.