我在看https://en.cppreference.com/w/cpp/language/reinterpret_cast,我注意到它指定了我们总是可以投射到的合法类型:
byte*
char*
unsigned char*
但我没有在列表中看到void*
。这是疏忽吗?我的用例需要一个reinterpret_cast
因为我从int**
铸造到void*
。我最终会从void*
回到int**
。
从指针转换为类型到指向包含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 for C ++ 17中说过8.2.10重新解释cast [expr.reinterpret.cast],§7
当对象指针类型的prvalue v转换为对象指针类型“指向cv T的指针”时,结果为
static_cast<cv T*>(static_cast<cv void*>(v))
。
当您将byte和char称为唯一合法类型时,仅仅针对这些类型取消引用转换后的指针是合法的。 void
不包括在这里因为你永远不能解除引用void *
。
专门回答你的问题
..我正在从int **转换为void *。而且我最终会从void *转变为int **。
该标准保证第一个是标准(读隐式)转换:
类型为“指向cv T的指针”的prvalue,其中T是对象类型,可以转换为类型为“指向cv void的指针”的prvalue。此转换不会改变指针值(6.9.2)。
所以这总是合法的:
int **i = ...;
void *v = i;
对于背铸,标准说(在static_cast
段):
类型为“指向cv1 void的指针”的prvalue可以转换为类型为“指向cv2 T的指针”的prvalue,
所以这也是合法的
int **j = static_cast<int **>(v);
和标准确保j == i
。
这些类型不受严格别名规则的约束。这并不意味着它们是唯一可以与reinterpret_cast
一起使用的类型。在将对象指针转换为另一个对象指针类型的情况下,如果不满足严格别名规则的要求,则意味着您无法安全地取消引用结果。但是你仍然可以安全地将结果指针强制转换回原始类型,并使用结果as-if它是原始指针。
关于reinterpret_cast
的cppreference的相关部分:
(任何对象指针类型
T1*
都可以转换为另一个对象指针类型cvT2*
。这完全等同于static_cast<cv T2*>(static_cast<cv void*>(expression))
(这意味着如果T2
的对齐要求不比T1
更严格,则指针的值不会改变并转换为结果指针返回其原始类型会产生原始值。在任何情况下,如果类型别名规则允许,结果指针只能被安全地解除引用)
当回到原始类型时,AliasedType
和DynamicType
是相同的,所以它们是相似的,这是别名规则列出的第一个案例,其中取消引用reinterpret_cast
的结果是合法的:
每当尝试通过类型为
DynamicType
的glvalue读取或修改AliasedType
类型的对象的存储值时,除非满足下列条件之一,否则行为是未定义的:
AliasedType
和DynamicType
是相似的。AliasedType
是signed
的(可能是cv合格的)unsigned
或DynamicType
变种。AliasedType
是std::byte
,(自C ++ 17以来)char
或unsigned char
:这允许将任何对象的对象表示检查为字节数组。
可以将对象指针显式转换为不同类型的对象指针。
指向cv
void
的指针类型或指向对象类型的指针称为对象指针类型。
但是,您不需要使用reinterpret_cast
。指向类型为cv-unqualified的每个对象指针类型都可以隐式转换为void*
,而逆可以通过static_cast
完成。