C++ reinterpret_cast
通过重新解释潜在的比特模型(但没有进行相应的二进制转换)实现类型之间的转换。
如:
#include <iostream>
using namespace std;
int main(void)
{
int t = 3;
double d = reinterpret_cast<double&>(t);
cout << "t = " << t << endl
<< "d = " << d << endl;
return 0;
}
----
可能的结果:
t = 3
d = 6.95285e-308
语法
reinterpret_cast (expression);
返回new_type类型的值。
解释
与static_cast
不同,但和const_cast
相似,reinterpret_cast
表达式不会编译为任何CPU指令。它纯粹是一个编译器指令,指示编译器将表达式的比特(对象表示)序列对待为new_type
类型。
仅有以下转换可以通过reinterpret_cast完成,其中一些转换可能会丢失const与volatile。
整型、枚举、指针、指针,或成员指针类型的表达式可以转换为自身的类型。值的结果与表达式的值相同。
任意指针类型可以转换为整型类型,整型类型应该足够大以足以保存指针的值。例:·
std::uintptr_t
。任意整型或枚举类型的值可以转换为指针类型。指针和整型应保证以足够的大小相互转换,否则可能会导致指针不能被安全的解引用。null指针常量
NULL
或者整数0并不能保证转换指定类型的null指针值,可以通过static_cast
与隐式转换实现这一目的。任意
std::nullptr_t
类型的值,包括nullptr
可以转化为任意的整型类型,仿佛它们的是(void*)0
一样。但是没有值的话,即使是nullptr
也不能转换为std::nullptr_t
,可以通过使用static_cast
达到这一目的。任意指向类类型
T1
对象的指针可以转换为指向另一个类类型cv T2
的指针,等价于static_cast<cv T2*>(static_cast<cv void*>(expression))
,意味着如果T2
的对齐要求没有T1
严格,指针的值也不会发生改变,当将转换后的指针再转换为初始的类型会得到初始的值。总之,转换的指针仅当如满足类型别名规则时(如下条目说明),才可以被安全的解引用。一个类型为
T1
的左值表达式可以转换为另一个类型为T2
的引用。结果是一个指向初始左值对象的lvalue
或xvalue
,但是类型不同。没有临时对象创建,没有发生复制,也没有调用构造器或转换函数。转换的引用仅当满足类型别名规则时(如下条目说明),才可以被安全的访问。任意指向函数的指针可以转换为指向不同函数类型的指针。调用这个指向不同函数类型的指针是未定义的,但是再将这个指针转换回原来的函数指针,会得到指向原始函数类型的指针。
在一些实现上(特别地,在任何与POSIX兼容并需要
dlsym
的系统上),函数指针能够转换为void*
,或任意其它对象的指针,反之亦然。如果系统实现支持两个方向的转换,那么将转换后的指针转换回原来的指针,便会得到初始的值。否则,转换的转换的指针不能被安全的解引用。任意类型的空指针值可以转换为任意其它类型的指针,转换结果为目标类型的空指针值。注意,空指针常量
nullptr
或任意其它std::nullptr_t
类型的值不能通过reinterpret_cast
转换为指针。如果需要此种转换,可以通过隐式转换或static_cast
来实现。一个指向成员函数的右值指针可以指向不同类型不同成员函数的指针。当转换回初始类型可以得到原来的值,否则转换得到的指针不能被安全使用。
一个指向类类型
T1
成员对象的右值指针可以转换为另一个类类型T2
成员对象的右值指针。如果T2
的对齐要求没有T1
严格,并且转换到初始类型可以得到原来的值,否则转换得到的指针不能被安全使用。
正如其它转换表达式一样,转换结果又以下几种:
如果new_type是一个左值引用类型或引用函数类型的右值引用,那么结果是左值;
如果new_type是一个引用对象类型的右值引用,那么结果是xvalue;
其它情况是纯右值(prvalue);
关键字
reinterpret_cast
类型别名
当指针或引用是一个动态类型的指针或引用时,通过reinterpret_cast
转换该动态类型的别名类型时,转换始终是可以成功的。但是仅当动态类型(DynamicType)与别名类型(AliasedType)是标准布局类型(Standard-Layout Type),或者满足一下条件之一的,才可使用转换后的指针或引用访问对象。
别名类型是动态类型,也可能加了cv限定符(const or volatile);
别名类型与动态类型(可能是多层,也可能每一层加了cv限定符)都是指向同一类型
T
的指针(从C++11开始支持);别名类型是动态类型的有符号或无符号变量(可能加了cv限定符);
别名类型是一个聚合类型(aggregate type)或联合类型(union type)时,其中聚合类型与联合类型的成员的类型是上诉提到的几种类型,或者是非静态成员。这时可以转换获得给定结构体指针或联合指针的安全可用的指针,指向它的非静态成员或元素;
别名类型是动态类型的基类(可能加了cv限定符);
别名类型是char或unsigned char:这允许将任意对象的对象表示作为一个unsigned char数组来检查;
如果别名类型不满足这些要求,访问转换后的新指针或引用会发生未定义行为。这被称为严格别名规则(strict aliasing rules),并在C++与C语言都有应用。需要注意的是,一些C++编译器对语言标准作了非标准扩展,因此可能并不严格遵守这一规则,允许以错误的类型访问union中非活动的成员(该特性在C语言中是未定义的)。另外需要注意的是,这一规则集比C语言相应的别名规则要严格的多。C允许访问兼容类型的指针,而C++没有兼容类型,并且如果不满足以上规则,则不允许访问布局兼容的类型的指针或引用。
注意事项
C++不允许函数指针与void *
之间的转换。
例子
#include <cstdint>
#include <cassert>
#include <iostream>
int f() { return 42; }
int main()
{
int i = 7;
// pointer to integer and back
uintptr_t v1 = reinterpret_cast<uintptr_t>(&i); // static_cast is an error
std::cout << "The value of &i is 0x" << std::hex << v1 << '
';
int* p1 = reinterpret_cast<int*>(v1);
assert(p1 == &i);
// pointer to function to another and back
void(*fp1)() = reinterpret_cast<void(*)()>(f);
// fp1(); undefined behavior
int(*fp2)() = reinterpret_cast<int(*)()>(fp1);
std::cout << std::dec << fp2() << '
'; // safe
// type aliasing through pointer
char* p2 = reinterpret_cast<char*>(&i);
if(p2[0] == 'x7')
std::cout << "This system is little-endian
";
else
std::cout << "This system is big-endian
";
// type aliasing through reference
reinterpret_cast<unsigned int&>(i) = 42;
std::cout << i << '
';
}
-----------
可能的输出结果:
The value of &i is 0x7fff352c3580
42
This system is little-endian
42
参见
const_cast转换
添加或移除const
static_cast转换
实现基本的转换
dynamic_cast转换
实现多态类型之间转换检查
explicit转换
类型之间的显示转换
standard转换
类型之间的隐式转换