混迹C++ 之reinterpret_cast和static_cast

时间:2022-09-11 12:06:25
reinterpret_cast <new_type> (expression)

reinterpret_cast运算符是用来处理无关类型之间的转换;它会产生一个新的值,

这个值会有与原始参数(expressoin)有完全相同的比特位。

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

  • 从指针类型到一个足够大的整数类型
  • 从整数类型或者枚举类型到指针类型
  • 从一个指向函数的指针到另一个不同类型的指向函数的指针
  • 从一个指向对象的指针到另一个不同类型的指向对象的指针
  • 从一个指向类函数成员的指针到另一个指向不同类型的函数成员的指针
  • 从一个指向类数据成员的指针到另一个指向不同类型的数据成员的指针

总结来说:reinterpret_cast用在任意指针(或引用)类型之间的转换;

以及指针与足够大的整数类型之间的转换;从整数类型(包括枚举类型)到指针类型,无视大小。

(所谓"足够大的整数类型",取决于操作系统的参数,如果是32位的操作系统,就需要整形(int)以上的;

如果是64位的操作系统,则至少需要长整形(long)。具体大小可以通过sizeof运算符来查看)。

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;
}

对整数的操作显然要对地址操作更方便。在集合中存放整形数值,也要比存放地址更具有扩展性

(当然如果存void *扩展性也是一样很高的),唯一损失的可能就是存取的时候整形和地址的转换

(这完全可以忽略不计)。

IBM的C++指南指出:reinterpret_cast不能像const_cast那样去除const修饰符

相关链接:http://www.cnblogs.com/ider/archive/2011/07/30/cpp_cast_operator_part3.html

一段代码示例:

#include <iostream>//www.fishc.com
int main()
{
const unsigned short ITEMS = 5;
int intArray[ITEMS] = {1,2,3,4,5};
char charArray[ITEMS] = {'F','i','s','h','C'};

int *intPtr = intArray;
char *charPtr = charArray;

std::cout << "整型数组输出:"<< '\n';
for(int i=0; i<ITEMS; i++)
{
std::cout << *intPtr << "at" <<reinterpret_cast<unsigned long>(intPtr)<<'\n';
//std::cout << *intPtr << "at" <<static_cast<unsigned int*>(intPtr)<<'\n';
std::cout << *intPtr << "at" <<intPtr<<'\n';
std::cout<<"-------------------------------"<<'\n';
intPtr++;
}
std::cout << "字符型型数组输出:" << '\n';
for(int i=0; i<ITEMS; i++)
{
std::cout << *charPtr << "at" <<reinterpret_cast<unsigned long>(charPtr) <<'\n';
std::cout << *charPtr << "at" <<charPtr <<'\n';
执行结果:

整型数组输出:
1at3214992192
1at0xbfa0e340
-------------------------------
2at3214992196
2at0xbfa0e344
-------------------------------
3at3214992200
3at0xbfa0e348
-------------------------------
4at3214992204
4at0xbfa0e34c
-------------------------------
5at3214992208
5at0xbfa0e350
-------------------------------
字符型型数组输出:
Fat3214992215
FatFishC
-------------------------------
iat3214992216
iatishC
-------------------------------
sat3214992217
satshC
-------------------------------
hat3214992218
hathC
-------------------------------
Cat3214992219
CatC
-------------------------------
 
注意:在转换前后没有数位损失。  

static_cast

转自百科名片

  用法:static_cast < type-id > ( expression )   

该运算符把expression转换为type-id类型,但没有运行时类型检查来保证转换的安全性。它主要有如下几种用法:

①用于类层次结构中基类(父类)和派生类(子类)之间指针或引用的转换。

 进行上行转换(把派生类的指针或引用转换成基类表示)是安全的;  

   进行下行转换(把基类指针或引用转换成派生类表示)时,由于没有动态类型检查,所以是不安全的。  

②用于基本数据类型之间的转换,如把int转换成char,把int转换成enum。这种转换的安全性也要开发人员来保证。  

③把空指针转换成目标类型的空指针。 

④把任何类型的表达式转换成void类型。  

注意:static_cast不能转换掉expression的const、volatile、或者__unaligned属性。  

C++中static_cast和reinterpret_cast的区别 

 C++primer第五章里写了编译器隐式执行任何类型转换都可由static_cast显示完成;

reinterpret_cast通常为操作数的位模式提供较低层的重新解释   

1、C++中的static_cast执行多态的转换,用于代替C中通常的转换操作。因此,被做为隐式类型转换使用。

比如:  

   int i;   

float f = 166.71;   

i = static_cast<int>(f);

此时结果,i的值为166。

2、C++中的reinterpret_cast主要是将数据从一种类型的转换为另一种类型。

所谓“通常为操作数的位模式提供较低层的重新解释”也就是说将数据以二进制存在形式的重新解释

比如:   

int i;   

char *p = "This is a example.";   

i = reinterpret_cast<int>(p);

此时结果,i与p的值是完全相同的。

reinterpret_cast的作用是说将指针p的值以二进制(位模式)的方式被解释为整型,并赋给i,//i 也是指针,整型指针