Reinterpret_cast与C风格演员

use*_*214 32 c++ casting

我听说这reinterpret_cast是实现定义,但我不知道这是什么意思.你能提供一个如何出错的例子,它出错了,使用C-Style演员会更好吗?

jal*_*alf 31

C风格的演员并不是更好.

它只是按顺序尝试各种C++风格的转换,直到找到一个有效的转换.这意味着,当它像a一样reinterpret_cast,它有一个完全相同的问题reinterpret_cast.但另外,它有这些问题:

  • 它可以做很多不同的事情,并且通过阅读代码调用哪种类型的强制转换(它可能表现为a reinterpret_cast,a const_cast或a static_cast,以及那些做非常不同的事情)并不总是很清楚.
  • 因此,更改周围的代码可能会更改强制转换的行为
  • 在阅读或搜索代码时很难找到 - reinterpret_cast很容易找到,这很好,因为演员表很难看,使用时应该注意.相反,(int)42.0通过搜索可以更加可靠地找到C风格的演员表(如同)

回答问题的其他部分,是的,reinterpret_cast是实现定义的.这意味着当您使用它从int*a 转换为a时float*,则无法保证结果指针将指向同一地址.那部分是实现定义的.但是,如果你承担由此产生float*reinterpret_cast它放回的int*,那么你会得到原来的指针.这部分是有保证的.

但同样,请记住,无论您使用reinterpret_castC样式还是使用C样式,都是如此:

int i;
int* p0 = &i;

float* p1 = (float*)p0; // implementation-defined result
float* p2 = reinterpret_cast<float*>(p0); // implementation-defined result

int* p3 = (int*)p1; // guaranteed that p3 == p0
int* p4 = (int*)p2; // guaranteed that p4 == p0
int* p5 = reinterpret_cast<int*>(p1); // guaranteed that p5 == p0
int* p6 = reinterpret_cast<int*>(p2); // guaranteed that p6 == p0
Run Code Online (Sandbox Code Playgroud)

  • @jalf 很好的答案,我在一个小时的谷歌搜索中找到了最好的答案。有一个吹毛求疵的分享:Stroustrup 在“The C++ Programming Language”中提到,为了保证从 A 到 B 到 A 的转换序列工作,`A` 的大小需要适合 `B` 的大小. 将指针投射到非指针字符并返回显然会导致流泪。不太明显的是,一些晦涩的硬件平台上指针的存储大小可能会因指向的类型而异,唯一的保证是 void* 需要能够适合它们中的任何一个。 (2认同)

Kon*_*hin 15

它是在某种意义上定义的实现,标准不会(几乎)规定不同类型值在位级别上应该是什么样子,应该如何构造地址空间等等.所以它真的是一个非常适合转换的平台,例如:

double d;
int &i = reinterpret_cast<int&>(d);
Run Code Online (Sandbox Code Playgroud)

但正如标准所说

对于那些了解底层机器的寻址结构的人来说,这并不奇怪.

因此,如果你知道你做了什么以及它在低级别上看起来如何,那么什么都不会出错.

C风格的强制转换在某种程度上类似于它可以执行reinterpret_cast,但它也首先"尝试"static_cast并且它可以抛弃cv资格(而static_cast和reinterpret_cast不能)并执行转换而忽略访问控制(参见5.4)/4在C++ 11标准中).例如:

#include <iostream>

using namespace std;

class A { int x; };
class B { int y; };

class C : A, B { int z; };

int main()
{
  C c;

  // just type pun the pointer to c, pointer value will remain the same
  // only it's type is different.
  B *b1 = reinterpret_cast<B *>(&c);

  // perform the conversion with a semantic of static_cast<B*>(&c), disregarding
  // that B is an unaccessible base of C, resulting pointer will point
  // to the B sub-object in c.
  B *b2 = (B*)(&c);

  cout << "reinterpret_cast:\t" << b1 << "\n";
  cout << "C-style cast:\t\t" << b2 << "\n";
  cout << "no cast:\t\t" << &c << "\n";
}
Run Code Online (Sandbox Code Playgroud)

这是ideone的输出:

reinterpret_cast:  0xbfd84e78
C-style cast:      0xbfd84e7c
no cast:           0xbfd84e78

请注意,reinterpret_cast生成的值与'c'的地址完全相同,而C样式转换导致正确的偏移指针.

  • @edA-qa mort-ora-y:假设整数足够大以容纳指针。最重要的一个(IMO)是从 A* -&gt; void* -&gt; A* 的往返产生原始的。 (2认同)

edA*_*a-y 5

有正当理由可以使用reinterpret_cast,由于这些原因,标准实际上定义了会发生什么.

第一种是使用不透明的指针类型,既可以用于库API,也可以用于在单个数组中存储各种指针(显然还有它们的类型).您可以将指针转换为适当大小的整数,然后返回指针,它将是完全相同的指针.例如:

T b;
intptr_t a = reinterpret_cast<intptr_t>( &b );
T * c = reinterpret_cast<T*>(a);
Run Code Online (Sandbox Code Playgroud)

在此代码c中保证指向b您期望的对象.转换回不同的指针类型当然是未定义的(有点).

函数指针和成员函数指针允许类似的转换,但在后一种情况下,您可以转换为/从另一个成员函数指针转换,只是为了拥有一个大的enouhg变量.

第二种情况是使用标准布局类型.这是在C++ 11之前支持的因素,现在已在标准中指定.在这种情况下,标准将reinterpret_cast视为static_cast,先将void*视为void*,然后将static_cast视为desination类型.在进行二进制协议时会使用这种方法,其中数据结构通常具有相同的头信息,并允许您转换具有相同布局但C++类结构不同的类型.

在这两种情况下,您应该使用显式reinterpret_cast运算符而不是C样式.虽然C风格通常会做同样的事情,但它有遭受过载转换运算符的危险.


Ayj*_*jay 4

C++ 具有类型,它们之间通常相互转换的唯一方式是通过您编写的明确定义的转换运算符。一般来说,这就是您编写程序所需要并且应该使用的全部内容。

然而,有时您希望将表示类型的位重新解释为其他内容。这通常用于非常低级的操作,通常不应该使用。对于这些情况,您可以使用reinterpret_cast.

它是实现定义的,因为 C++ 标准并没有真正说明事物应该如何在内存中布局。这是由您的 C++ 特定实现控制的。因此, 的行为reinterpret_cast取决于编译器如何在内存中布置结构以及它如何实现reinterpret_cast.

C 风格的转换与 s 非常相似reinterpret_cast,但它们的语法要少得多,因此不推荐。人们的想法是,强制转换本质上是一种丑陋的操作,它需要丑陋的语法来通知程序员正在发生可疑的事情。

一个简单的例子说明它可能会出错:

std::string a;
double* b;
b = reinterpret_cast<double*>(&a);
*b = 3.4;
Run Code Online (Sandbox Code Playgroud)

该程序的行为是未定义的 - 编译器可以对此执行任何操作。最有可能的是,当调用 的析构函数时,您会崩溃string,但谁知道呢!它可能只会损坏您的堆栈并导致不相关的函数崩溃。

  • 1.3.10 **实现定义的行为** 对于格式良好的程序构造和正确的数据,该行为取决于实现以及每个实现文档。1.3.24:**未定义的行为**本国际标准没有提出要求的行为。1.3.25 **未指定的行为** 对于格式良好的程序构造和正确的数据而言,行为取决于实现。在这里获取标准的副本:http://stackoverflow.com/questions/81656/where-do-i-find-the-current-c-or-c-standard-documents/4653479#4653479 (3认同)