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

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

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

时间: 2024-11-15 07:10:18

【转】C++标准转换运算符reinterpret_cast的相关文章

C++标准转换运算符reinterpret_cast

文章出处:http://www.cnblogs.com/ider/archive/2011/07/30/cpp_cast_operator_part3.html reinterpret_cast <new_type> (expression) reinterpret_cast运算符是用来处理无关类型之间的转换:它会产生一个新的值,这个值会有与原始参数(expressoin)有完全相同的比特位. 什么是无关类型?我没有弄清楚,没有找到好的文档来说明类型之间到底都有些什么关系(除了类的继承以外).

C++标准转换运算符dynamic_cast

dynamic_cast <new_type> (expression) dynamic_cast运算符,应该算是四个里面最特殊的一个,因为它涉及到编译器的属性设置,而且牵扯到的面向对象的多态性跟程序运行时的状态也有关系,所以不能完全的使用传统的转换方式来替代.但是也因此它是最常用,最不可缺少的一个运算符. 与static_cast一样,dynamic_cast的转换也需要目标类型和源对象有一定的关系:继承关系. 更准确的说,dynamic_cast是用来检查两者是否有继承关系.因此该运算符实

C++标准转换运算符

参考 : [1]. Type conversions.  http://www.cplusplus.com/doc/tutorial/typecasting/ [2]. C++标准转换运算符. http://www.cnblogs.com/ider/archive/2011/07/22/cpp_cast_operator_part2.html

C++标准转换运算符const_cast

文章出处:http://www.cnblogs.com/ider/archive/2011/07/22/cpp_cast_operator_part2.html 前面讲了C++继承并扩展C语言的传统类型转换方式,最后留下了一些关于指针和引用上的转换问题,没有做详细地讲述.C++相比于C是一门面向对象的语言,面向对象最大的特点之一就是具有“多态性(Polymorphism)”. 要想很好的使用多态性,就免不了要使用指针和引用,也免不了会碰到转换的问题,所以在这一篇,就把导师讲的以及在网上反复查阅了

C++标准转换运算符static_cast

由于作者不习惯该编辑器,只是贴出上本文的截图,详见:https://www.yuque.com/docs/share/0f6248e7-36d4-43b6-807a-7ca66ab0b8ac 原文地址:http://blog.51cto.com/4754569/2327436

十四、C# 支持标准查询运算符的集合接口

支持标准查询运算符的集合接口. System.Linq.Enumeralbe类提供的一些常用的API 来执行集合处理 1.匿名类型 2.隐匿类型的局部变量 3.集合初始化器 4.集合 5.标准查询运算符 本章主要讨论泛型集合接口. 非泛型的集合类,待查. 一.匿名类型和隐式类型的局部变量声明 C#3.0增强. 1.匿名类型 一种特殊的数据类型,它最终是由编译器声明的,而非通过已定义好的类来声明的. 和匿名函数相似,当编译器看到一个匿名类型时,会自动执行一些后台操作,生成必要的代码, 允许像显式声

C++语言定义的标准转换

标准转换 C++ 语言定义其基础类型之间的转换. 它还定义指针.引用和指向成员的指针派生类型的转换. 这些转换称为"标准转换. 1. 整型提升 整数类型的对象可以转换为另一个更宽的整数类型(即,可表示更大的一组值的类型). 这种扩展类型的转换称为"整型提升". 利用整型提升,您可以在可使用其他整数类型的任何位置将以下项用于表达式: char 和 short int 类型的对象.文本和常量 枚举类型 int 位域 枚举器 C++ 提升是"值保留". 即,提升

LinQ转换运算符OfType&lt;T&gt;

using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace OfTypeDemo { class Program { static void Main(string[] args) { var numbers = new object[] { 1, "two", null, "3", 4 }; foreach (var anInt in

.NET中那些所谓的新语法之四:标准查询运算符与LINQ

开篇:在上一篇中,我们了解了预定义委托与Lambda表达式等所谓的新语法,这一篇我们继续征程,看看标准查询运算符和LINQ.标准查询运算符是定义在System.Linq.Enumerable类中的50多个为IEnumerable<T>准备的扩展方法,而LINQ则是一种类似于SQL风格的查询表达式,它们可以大大方便我们的日常开发工作.因此,需要我们予以关注起来! /* 新语法索引 */ 1.自动属性 Auto-Implemented Properties 2.隐式类型 var 3.参数默认值 和