我听说这reinterpret_cast
是实现定义,但我不知道这是什么意思.你能提供一个如何出错的例子,它出错了,使用C-Style演员会更好吗?
jal*_*alf 31
C风格的演员并不是更好.
它只是按顺序尝试各种C++风格的转换,直到找到一个有效的转换.这意味着,当它像a一样reinterpret_cast
,它有一个完全相同的问题reinterpret_cast
.但另外,它有这些问题:
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_cast
C样式还是使用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)
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样式转换导致正确的偏移指针.
有正当理由可以使用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风格通常会做同样的事情,但它有遭受过载转换运算符的危险.
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
,但谁知道呢!它可能只会损坏您的堆栈并导致不相关的函数崩溃。
归档时间: |
|
查看次数: |
29099 次 |
最近记录: |