C++中static_cast、const_cast、reinterpret_cast的用法举例,附带举例说明强制类型转换时int和int&的区别

《C++ Primer中文版》(第4版)的5.12.6节介绍static_cast、const_cast、reinterpret_cast的用法:

1、static_cast,编译器隐式执行的任何类型转换都可以由static_cast显示完成,如:

double d=97.0
char c1=d;//warning
char c2=static_cast<char>(d);//ok

也就是说,static_cast可以把编译器的warning关掉。当需要将一个较大的算数类型赋值给较小的类型时,使用static_cast强制转换非常有用。


2、const_cast,添加或删除const特性,如:

const int &val=13;
int &ncref=const_cast<int>(&val);//删除const特性
int &cref=const_cast<const int&>(ncref);//添加const特性

注意,可以给const变量使用const_cast<const XXX>转换,也可以给非const继续使用const_cast<XXX>转换,不会报错。

const_cast只能用来添加或删除const特性,不能作他用,否则编译报错,如:

const int &val=13;
int &ncref=const_cast<int>(val);//error,不能将const int转换成int

而此时换成static_cast编译正常:

const int &val=13;
const int &ncref=static_cast<int>(val);//ok
注意,在G++中,此时的ncref必须定义成const(因为static_cast在转换时产生了一个临时变量),否则报错;

在VS2005中不用定义成const,不产生临时对象,不报错……


因为int和int&是不相同的类型:

用int转换时,会产生int型临时对象,该对象是编译器对被转换的内存空间按照某一规则进行的数值上的转换,如将float转换成int时,就是对float占据的内存空间里的数据进行的基于IEEE浮点数定义的规则上的转换,0.0->0,1.0->1,2.5->2等。

用int&转换时,不会产生任何临时对象,完全是使用int类型强制解释被转换的内存空间,而不是基于数值上的转换,同样用float转换成int举例:

float   1.0在内存中存储为: 
符号位     阶(指数)       尾数 
0               01111111       00000000000000000000000 

关于浮点数存储可以参见有关标准。 

转化为int&后,数据就变为00111111100000000000000000000000   =   1065353216

3、interpret_cast通常为操作数的位模式提供较低层次的重新解释。

/*将float转成int&是对原float变量所占用内存空间的重新解释(以int类型读取float的二进制形式的数据)
**由于这种转换不会由编译器自动完成,所以使用static_cast<int&>报错
**应该使用reinterpret_cast<int&>,
**而static_cast<int>在此处相当于(int)fval,是基于IEEE的浮点数规范的转换,保持了数值的一致性
**/
float fval=1.0f;
cout<<"reinterpret_cast<int&>="<<reinterpret_cast<int&>(fval)//1065353216
	<<",static_cast<int>(dval)="<<static_cast<int>(fval)<<endl;//1


综上,

1、static_cast只能用来完成编译器能自动完成的或出现warning的类型转换,将一个较大的算数类型赋值给较小的数据类型(double=>int,int=>char等),

或在相同大小的数据类型间转换(int&=>int,double&=>double等)(在G++中,static_cast<int>时会产生临时对象,static_cast<int&>时不会产生临时对象;在VS2005中都不会产生临时对象……)

但是,static_cast不会完成const到非const的转换,也不会把一个float值所占的内存空间当成int来操作(如static_cast<int&>(1.0f)),因为编译器也不会这么干的!


2、const_cast仅用来添加或删除const特性,而不能用于类型转换,注意int和int&不是同一个类型!


3、reinterpret_cast用于二进制层次的重新解释,如将float或double所占的内存空间当成int来解释,而不是基于IEEE浮点数定义规则上的转换。


以上3种命名的强制类型转换是C++语言规范的一部分,而不是C里的,因为C++兼容C,所以,C里的强制类型转换语法在C++中也适用:

const int &val=2;
float fval=1.0f;

//const_cast<int&>
int &ncref1=(int&)(val);//ok
ncref1=10;
//int &ncref2=val;//error,不能将const变量赋值给非const引用
cout<<"ncref1="<<ncref1<<",val="<<val<<endl;

//static_cast<int>
int ival1=(int)fval;//ok
int ival2=fval;//ok,float与int位数相等;如果将double赋值给int,则出现warning

//reinterpret_cast<int&>
int &iref1=(int&)fval;
cout<<"iref1="<<iref1<<endl;

//static_cast<int>
const int &iref2=(int)fval;//由于返回的是临时int变量,所以必须使用const修饰
cout<<"iref2="<<iref2<<endl;

上面代码中,关于const_cast的代码段,如果修改成:

const int val=2;

//const_cast<int>
int &ncref1=(int&)(val);//ok,VS2005中偶尔运行时报错,G++中编译运行都不报错
//上式等价于int &ncref1=const_cast<int&>(static_cast<const int&>(val));

ncref1=10;
//ncref1=10,val=2
cout<<"ncref1="<<ncref1<<",val="<<val<<endl;

则得不到预期的效果:ncref1=10,val=10,因为val被声明为const,就无法改变它的值。注意之前用const_cast删除const特性的例子,用的都是引用(int&),有什么区别呢?

const int & val=2;表示我分配了一个int变量的空间,这个空间没有名字,其值为2,然后我用val这个名字来指代这个空间,由于我在定义这个名字的时候,用了const定义,所以,我不能通过这个这个名字(val)去修改对应内存空间的值。但是,我可以通过别的名字来修改这个内存空间的值,只要将val的地址告诉别的引用或者指针就行了!

const int val=2;表示我分配了一个int变量的空间,这个空间的名字叫val,而且这个空间是const的,不能通过这个名字(val)或其他任何名字来修改这个内存空间的值!


参考资料:

1、C/C++左值性精髓(二)哪些表达式是左值,哪些是右值?--- 函数调用表达式和强制转换

2、一道C++的题目 关于(int)与(int &)

3、(int)a、&a、(int)&a、(int&)a的区别


附上剩余实验代码:

void test(){
	const char *pc_str="hello";
	char *pc=(char*)(pc_str);
	//pc[0]='w';//error,不可以赋值,因为pc[0]指向的毕竟是常量字段区("hello")

	int i=13;
	int j=13;
	int k=13;
	const int &val=13;//用常量给const引用赋值时,应该是分配了变量存储空间
	const int &cref=val;

	/*(int&)val是将val的内存空间直接按照int型读取(不进行数值上的转换,不可以完成float到int的数值上的转换)
	**(int)val是将val的内存空间里的数据按照IEEE规则转换数值(如可以完成float到int在数值上的转换)
	**参见:
	**http://topic.csdn.net/u/20070618/15/64bf9e83-c422-43aa-a451-5deed812e947.html
	**和
	**http://talentluke.iteye.com/blog/789841
	**/
	int &ncref1=(int&)val;
	int &ncref2=const_cast<int&>(val);
	//const_cast<const int&>(val);//可以将const转换成const;同理,也可以将非const转换成非const

	//这个转换应该使用const_cast完成
	//int &ncref3=static_cast<int&>(val);//error,static_cast只能做编译器默认进行的转换
	
	//在下面两句话中,(int)与static_cast<int>功能相同
	//int &ncref4=(int)val;//在VS2005中ok;在G++中error,因为(int)强转时,生成了临时变量,是const型的
	//int &ncref5=static_cast<int>(val);//在VS2005中ok;在G++中error,原因同上

	//int &ncref6=const_cast<int>(val);//error,const_cast只能增/删const属性,不能转换类型(int&转int)
	//int &ncref7=static_cast<int&>(val);//error,不能把const int&转换成int
	//int &ncref8=val;//error,不能把const int&转换成int&

	cout<<&i<<","<<&j<<","<<&k<<","<<&val<<","<<&cref<<","<<&ncref2<<endl;

	cout<<"初始值:"<<endl;
	cout<<"i="<<i<<",val="<<val<<",cref="<<cref<<",ncref1="<<ncref1<<",ncref2="<<ncref2<<endl;

	/*数值都被改变
	**C++中的const属性只是限制程序通过const变量修改某内存空间,
	**但是可以通过其他非const变量修改这块内存空间
	**/
	ncref2=10;
	cout<<"结果值:"<<endl;
	cout<<"i="<<i<<",val="<<val<<",cref="<<cref<<",ncref1="<<ncref1<<",ncref2="<<ncref2<<endl;

	/*将float转成int&是对原float变量所占用内存空间的重新解释(以int类型读取float的二进制形式的数据)
	**由于这种转换不会由编译器自动完成,所以使用static_cast<int&>报错
	**应该使用reinterpret_cast<int&>,
	**而static_cast<int>在此处相当于(int)fval,是基于IEEE的浮点数规范的转换,保持了数值的一致性
	**/
	float fval=1.0f;
	cout<<"reinterpret_cast<int&>="<<reinterpret_cast<int&>(fval)
		<<",static_cast<int>(dval)="<<static_cast<int>(fval)<<endl;
}

int _tmain(int argc, _TCHAR* argv[])
{
	int i(1);
	
	test();

	cin>>i;
	return 0;
}


你可能感兴趣的:(C++,c,存储,float,编译器)