C++标准转换运算符reinterpret_cast

reinterpret_cast <new_type> (expression)

reinterpret_cast运算符是用来拍卖无关类型之间的更换;它会时有暴发一个新的值,那么些值会有与原来参数(expressoin)有完全相同的比特位。

怎么是无关类型?我未曾弄了然,没有找到好的文档来表达类型之间究竟都有些什么关系(除了类的接续以外)。后半句倒是看出了reinterpret_cast的字面意思:重新诠释(类型的比特位)。我们实在可以无限制将一个类型值的比特位交给另一个系列作为它的值吗?其实不然。

IBM的C++指南里倒是明确报告了俺们reinterpret_cast可以,或者说应该在怎么地点用来作为转换运算符:

  • 从指针类型到一个充分大的平头类型
  • 从整数类型或者枚举类型到指针类型
  • 从一个对准函数的指针到另一个不同体系的针对函数的指针
  • 从一个针对对象的指针到另一个不比类型的指向对象的指针
  • 从一个对准类函数成员的指针到另一个对准不同序列的函数成员的指针
  • 从一个指向类数据成员的指针到另一个针对性不同类型的数额成员的指针

唯独我在Xcode中测试了一晃,事实上reinterpret_cast的利用并不囿于在上方所说的几项的,任何类型的指针之间都可以互相转换,都不会获取编译错误。上述列出的几项,可能
是Linux下reinterpret_cast使用的限定,也恐怕是IBM推荐我们拔取reinterpret_cast的方式

由此总括来说:reinterpret_cast用在自由指针(或引用)类型之间的转换;以及指针与丰盛大的整数类型之间的转移;从整数类型(包括枚举类型)到指针类型,无视大小。

(所谓”充裕大的整数类型”,取决于操作系统的参数,假设是32位的操作系统,就需要整形(int)以上的;如倘若64位的操作系统,则至少需要长整形(long)。具体大小可以由此sizeof运算符来查看)。

reinterpret_cast有何意义

从下边对reinterpret_cast介绍,可以感到出reinterpret_cast是个很强大的运算符,因为它可以漠视种族隔离,随便搞。但就像生物的准则,不相符自然规律的任性杂交只会拿到不可能长久生存的物种。随意在不同档次之间选拔reinterpret_ACCESS,cast,也随后导致程序的毁损和不能够利用。

譬如说下边的代码
typedef int (*FunctionPointer)(int); int value = 21; FunctionPointer funcP; funcP = reinterpret_cast<FunctionPointer> (&value); funcP(value);

本人先用typedef定义了一个对准函数的指针类型,所针对的函数接受一个int类型作为参数。然后我用reinterpret_cast将一个整型的地方转换成该函数类型并赋值给了相应的变量。最终,我还用该整形变量作为参数交给了指向函数的指针变量。

以此进程编译器都成功的编译通过,但是只要运行我们就会赢得”EXC_BAD_ACCESS”的运作错误,因为我们透过funcP所指的地点找到的并不是函数入口。

估量,reinterpret_cast尽管接近强大,效用却不曾那么广。IBM的C++指南、C++之父Bjarne
Stroustrup的FAQ网页
MSDN的Visual
C++
也都指出:错误的施用reinterpret_cast很容易导致程序的不安全,唯有将转移后的类型值转换回到其原始类型,这样才是毋庸置疑行使reinterpret_cast方式。

如此说起来,reinterpret_cast转换成另外门类的目标只是暂时的藏身自己的怎么(做个卧底?),要真想选拔特别值,依然需要让其显露真面目才行。那究竟它在C++中有其何存在的市值呢?

MSDN的Visual C++ Developer
Center
 给出了它的采取价值:用来帮忙哈希函数。下面是MSNDN上的例子:

                // expre_reinterpret_cast_Operator.cpp
// compile with: /EHsc
#include <iostream>
// Returns a hash code based on an address
unsigned short Hash( void *p ) {
    unsigned int val = reinterpret_cast<unsigned int>( p );
    return ( unsigned short )( val ^ (val >> 16));
}

using namespace std;
int main() {
    int a[20];
    for ( int i = 0; i < 20; i++ )
        cout << Hash( a + i ) << endl;
}

//如果跟我一样是64位的系统,可能需要将unsigned int改成 unsigned long才能运行。

这段代码适合显示哈希的商讨,暂时不做探索,但起码看Hash函数里面的操作,也能体会到,对整数的操作显然要对地点操作更有利于。在聚集中存放整形数值,也要比存放地方更具有扩大性(当然假诺存void
*扩大性也是同样很高的),唯一损失的或者就是存取的时候整形和地点的转移(这点一滴可以忽略不计)。

然而可读性可能就不高,所以在那种景观下采纳的时候,就可以用typedef来定义个指针类型:
typedef unsigned int PointerType;

诸如此类不是更棒,当大家在64位机器上运行的时候,只要改成:
typedef unsigned long PointerType;

当reinterpret_cast面对const

IBM的C++指南指出:reinterpret_cast不能像const_cast这样去除const修饰符。
那是什么样意思啊?代码依旧最直观的公布:

int main() 
{
    typedef void (*FunctionPointer)(int);
    int value = 21;
    const int* pointer = &value;

    //int * pointer_r = reinterpret_cast<int*> (pointer); 
    // Error: reinterpret_cast from type 'const int*' to type 'int*' casts away constness

    FunctionPointer funcP = reinterpret_cast<FunctionPointer> (pointer);
}

事例里,大家像前面const_cast一篇举到的例证这样,希望将针对const的指针用运算符转换成非指向const的指针。可是当实用reinterpret_cast的时候,编译器直接报错协会了该过程。这就反映出了const_cast的例外之处。

可是,例子中还有一个转换是将针对const
int的指针付给指向函数的指针,编译顺利经过编译,当然结果也会跟前边的例证一样是空虚的。

假如我们换一种角度来看,这似乎也是合理合法的。因为
const int* p = &value;int * const q = &value;

这五个语句的意义是见仁见智的,前者是”所指内容不可变”,后者则是”指向的地点不可变”(实际参考此处)。由此指向函数的指针默认应该就隐含”所指内容不可变”的特征。

到底函数在编译之后,其操作过程就定位在这边了,大家唯一能做的就是传递一些参数给指针,而望洋兴叹转移已编译函数的过程。所以从这么些角度来想,上面例子使用reinterpret_cast从const
int * 到FunctionPointer转换就变得在理了,因为它并不曾删除const限定

Director: Jim
Fawcett

  1. C++ Language Tutorial – Type
    Casting
  2. Object Oriented
    Design
  3. IBM Complilers – XL C/C++ V9.0 for Linux – The reinterpret_cast
    operator (C++
    only)
  4. Bjarne Stroustrup’s C++ Style and Technique
    FAQ
  5. MSDN Visual C++ Developer Center – reinterpret_cast
    Operator

相关文章