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_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限定

【C/C++学习】之六、reinterpret_cast

reinterpret_cast <new_type> (expression)

reinterpret_cast是强制类型转换符!他是用来处理无关类型转换的,通常为操作数的位模式提供较低层次的重新解释!但是他仅仅是重新解释了给出的对象的比特模型,并没有进行二进制的转换!

他是用在任意的指针之间的转换,引用之间的转换,指针和足够大的int型之间的转换,整数到指针的转换,在家面的文章中将给出!

来看一个例子:

  1. int *pi;
  2. char *pc = reinterpret_cast<char*>(pi);

OK, 在这里你可以看到reinterpret_cast的强大作用,但是要注意的是,他并没有进行二进制的转换,pc指向的真实对象其实还是int的,不是char~

对于reinterpret_cast运算符要谨慎使用,下面给出一些使用的地方:

参考IBM C++

  • A pointer to any integral type large enough to hold it    (指针转向足够大的整数类型)
  • A value of integral or enumeration type to a pointer (从整形或者enum枚举类型转换为指针)
  • A pointer to a function to a pointer to a function of a different type (从指向函数的指针转向另一个不同类型的指向函数的指针)
  • A pointer to an object to a pointer to an object of a different type (从一个指向对象的指针转向另一个不同类型的指向对象的指针)
  • A pointer to a member to a pointer to a member of a different class or type, if the types of the members are both function types or object types  (从一个指向成员的指针转向另一个指向类成员的指针!或者是类型,如果类型的成员和函数都是函数类型或者对象类型)
这些是IBM C++推荐给我们的使用方式!
 
 reinterpret_cast是为了映射到一个完全不同类型的意思,这个关键词在我们需要把类型映射回原有类型时用到它。我们映射到的类型仅仅是为了故弄玄虚和其他目的,这是所有映射中最危险的。(这句话是C++编程思想中的原话)

大家使用的时候千万记住,不要乱使用!错误使用很容易导致程序的不安全!

Misuse of the reinterpret_cast operator
can easily be unsafe.  这是MSDN 的原话!

当然reinterpret_cast对 const, volatile, or __unaligned 也是没有用处的!

MSDN 上面给了一个实际的用处:哈希函数辅助

  1. // expre_reinterpret_cast_Operator.cpp
  2. // compile with: /EHsc
  3. #include <iostream>
  4. // Returns a hash code based on an address
  5. unsigned short Hash( void *p ) {
  6. unsigned int val = reinterpret_cast<unsigned int>( p );
  7. return ( unsigned short )( val ^ (val >> 16));
  8. }
  9. using namespace std;
  10. int main() {
  11. int a[20];
  12. for ( int i = 0; i < 20; i++ )
  13. cout << Hash( a + i ) << endl;
  14. }

主要是涉及数据在内存中的表示。

看看下面的代码:

C/C++ code

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream> 
using namespace std;
 
void main() 
    int i = 875770417;  //在内存中的表示从低位到高位依次是0x31 0x32 0x33 0x34
    cout<<i<<" ";
    char* p = reinterpret_cast<char*>(&i);
    for(int j=0; j<4; j++)
        cout<<p[j];
    cout<<endl;
 
    float f = 0.00000016688933;  //在内存中的表示从低位到高位依次也是0x31 0x32 0x33 0x34
    cout <<f<<" ";
    p = reinterpret_cast<char*>(&f);
    for(j=0; j<4; j++)
        cout<<p[j];
    cout<<endl;
}

不管是int型的i还是float型的f,经过reinterpret_cast<char*>(&addr)的转换后,输出都是"1234"
数据的表示相同,就看编译器怎么来解释数据,也就是语义表达的问题。
reinterpret_cast的转换就是不理会数据本来的语义,而重新赋予它char*的语义。

reinterpret_cast<char*>(&st) 这个怎么理解

reinterpret_cast是C++新标准下的强制类型转换,这里将&st的指针转换为char*型

C++标准转换运算符reinterpret_cast的更多相关文章

  1. 【转】C++标准转换运算符reinterpret_cast

    reinterpret_cast<new_type> (expression) reinterpret_cast运算符是用来处理无关类型之间的转换:它会产生一个新的值,这个值会有与原始参数 ...

  2. C++标准转换运算符

    C++类型转换在实际编程中会经常使用,其实,本质上对象的类型用来解释(interpret)对象.因为,每个对象都占据一块内存空间,这块内存空间存放了一段二进制数据.通过标记该对象的类型,告诉如何看待这 ...

  3. C++标准转换运算符const_cast

    前面讲了C++继承并扩展C语言的传统类型转换方式,最后留下了一些关于指针和引用上的转换问题,没有做详细地讲述.C++相比于C是一门面向对象的语言,面向对象最大的特点之一就是具有“多态性(Polymor ...

  4. C++标准转换运算符 --四种

    具体归纳如下: reinterpret_cast 函数将一个类型的指针转换为另一个类型的指针. 这种转换不用修改指针变量值存放格式(不改变指针变量值),只需在编译时重新解释指针的类型就可做到.rein ...

  5. C++标准转换运算符dynamic_cast

    dynamic_cast <new_type> (expression) dynamic_cast运算符,应该算是四个里面最特殊的一个,因为它涉及到编译器的属性设置,而且牵扯到的面向对象的 ...

  6. C++标准转换运算符static_cast

    该运算符把expression转换为type-id类型,但没有运行时类型检查来保证转换的安全性.   中文名 暂无 外文名 static_cast 分    类 强制类型转换 类    型 C++ s ...

  7. 【转】C++标准转换运算符static_cast

    static_cast<new_type> (expression) 虽然const_cast是用来去除变量的const限定,但是static_cast却不是用来去除变量的static引用 ...

  8. 【转】C++标准转换运算符const_cast

    const_cast转换符是用来移除变量的const或volatile限定符. 对于const变量,我们不能修改它的值,这是这个限定符最直接的表现.但是我们就是想违背它的限定希望修改其内容怎么办呢? ...

  9. const_cast标准转换运算符

    #include <iostream> using namespace std; class A { public: A() { a=; } public: int a; }; void ...

随机推荐

  1. 域策略禁用usb

    文档及模板可在 http://pan.baidu.com/s/1qYTcjTy  下载 pro_usb_users.adm  此模板可禁用到 指定盘符,针对用户策略 pro_usb_computers ...

  2. LUA GC 简单测试

    function table.count(t) if type(t) ~= "table" then assert(false) return end for k, _ in pa ...

  3. C#泛型-模板特化

    class TClass<T, K> { } class SubTClass<T, C, K> : TClass<Char, K> { } class SubTCl ...

  4. [转]在 Eclipse 中嵌入 NASA World Wind Java SDK

    使用此开源 SDK 开发 GIS 应用程序 NASA 开发的开源 World Wind Java (WWJ) SDK 为地理信息系统(Geographic Information Systems,GI ...

  5. UIPasteboard的使用

    剪贴板的使用以及自定义剪贴板. 系统剪贴板的直接调用 其实整个过程非常的简单,我就用我写的一个自定义UILable来说明调用系统剪贴板. 首先,因为苹果只放出来了 UITextView,UITextF ...

  6. SDAccel-FPGA将带来至多25倍单位功耗性能提升

    很久没有看FPGA了,本来想继续学习HLS,就上Xilinx的网站看了看.结果发现了SDx 开发环境,很新的一个东西.由于我对这方面了解不多,本篇博文仅仅只是资料的整合和介绍. 1.SDx开发环境 X ...

  7. webSocket实现web及时聊天的例子

    概述 websocket目前虽然无法普及应用,未来是什么样子,我们不得而知,但现在开始学习应用它,只有好处没有坏处,本随笔的WebSocket是版本13(RFC6455)协议的实现,也是目前webso ...

  8. [CH#58解题报告]

    题目:http://206.contesthunter.org/contest/CH%20Round%20%2358%20-%20OrzCC%E6%9D%AFnoip%E6%A8%A1%E6%8B%9 ...

  9. javamail技术

    package com.zh.javaEmail; import java.util.*; import javax.mail.*; import javax.mail.internet.*; imp ...

  10. 视频播放用户行为记录之使用Cache的方法

    在上一篇文章http://www.cnblogs.com/ryuasuka/p/3483632.html中,为了获取视频播放时的用户行为,并且要异步地将其写入XML文件中,我采用了先写入log,后生成 ...