reinterpret_cast无效是合法的*

时间:2019-04-17 13:31:02

标签: c++ pointers void-pointers reinterpret-cast double-pointer

我看着https://en.cppreference.com/w/cpp/language/reinterpret_cast时,发现它指定了我们可以始终转换为的合法类型:

  • byte*
  • char*
  • unsigned char*

但是我没有不是看到列表中的void*。这是疏忽吗?我的用例需要一个reinterpret_cast,因为我是从一个int**投射到一个void*。我最终将从void*投射回int**

3 个答案:

答案 0 :(得分:5)

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

reinterpret_cast上cppreference的相关部分:

  

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

当强制转换回原始类型时,AliasedTypeDynamicType是相同的,因此它们是相似的,这是别名规则列出的第一种情况,在这种情况下可以取消引用的结果reinterpret_cast

  

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

      
  • AliasedTypeDynamicType相似。
  •   
  • AliasedTypesigned的(可能具有简历资格)unsignedDynamicType的变体。
  •   
  • AliasedTypestd::byte,(自C ++ 17起)charunsigned char:这允许将任何对象的对象表示形式检查为字节数组。
  •   

答案 1 :(得分:4)

[expr.reinterpret.cast]/7

  

可以将对象指针显式转换为其他类型的对象指针。

[basic.compound]/3

  

指向 cv this.chartData = selectedRows // selected Rows are changed on selection 的指针或指向对象类型的指针的类型称为 object指针类型

不过,您无需使用void。每个指针类型为cv-unqualified的对象指针类型都可以隐式转换为reinterpret_cast,并且可以通过void*进行逆运算。

答案 2 :(得分:2)

将指针的类型转换为指向其他类型的指针(包括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的注意)

更明确地说,该标准甚至在C ++ 17的n4659草案中也提到了8.2.10重新解释演员表[expr.reinterpret.cast],第7章

  

当prvalue v为   对象指针类型转换为对象指针类型“ cv T的指针”,结果为static_cast<cv T*>(static_cast<cv void*>(v))

当您将byte和char称为唯一合法类型时,仅对这些类型的 dereference 转换后的指针是合法的。这里不包括void,因为您永远都不能取消引用void *


专门回答您的问题

  

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

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

  

“指针指向cv T”的prvalue(其中T是对象类型)可以转换为“ pointer的prvalue”类型   使简历无效”。转换后指针值(6.9.2)不变。

所以这始终是合法的:

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

对于反向投射,标准说(在static_cast段中):

  

“指针指向cv1无效”类型的prvalue可以转换为“指针指向cv2 T的类型”的prvalue,

所以这也是合法的

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

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