本节书摘来自华章出版社《C++程序设计教程(第3版)》一书中的第2章,第2.5节类型转换,作者张志航,更多章节内容可以访问云栖社区“华章计算机”公众号查看
2.5 类型转换
2.5.1 赋值时的自动类型转换
如果赋值运算符两侧的类型不一致,则遵循以下几条原则进行类型转换后赋值。
1.实型量赋给整型变量
实型量赋给整型变量时,简单舍弃小数部分,将实型量的整数部分赋给整型变量,不进行四舍五入。如“int i=3.96;”,则i被赋值为3。
2.整型量赋给实型变量
整型量赋给实型变量时,数值不变,有效数字位数增加。例如,若有“float f=23;”,则f获得的值为23.0,以单精度浮点格式存储,具有6~7位有效数字;若有“double d=23;”,则d获得的值为23.0,以双精度浮点格式存储,具有15~16位有效数字。
3.整型量之间相互赋值
整型量有8种,它们分别是[signed] char、unsigned char、[signed] short、unsigned short、[signed] int、unsigned int、[signed] long、unsigned long。此处将char型量看作1字节长度的整型量。各种类型的整型量占用的字节数是不同的,按照其二进制位数的多少,区分为“长的”整型量和“短的”整型量。所谓“长的”整型量是指该整型量的二进制位数较多,所谓“短的”整型量是指该整型量的二进制位数较少。整型量之间相互赋值,系统处理为它们内存数据之间的赋值,分两种情况。
(1)“长的”整型量赋给“短的”整型量
将“长的”整型量赋给“短的”整型量时,方法是“低位截断”,将“长的”整型量的高位去掉,截取其与“短的”整型量相同位数的低位二进制位,然后进行赋值。例如,“char c=250;”将int型常量250赋给字符型变量c。250为int整型常量,在内存中的存储形式是32位二进制数 0000 0000 0000 0000 0000 0000 1111 1010。变量c是8位有符号二进制整型量,赋值原则是取250内存数据的低8位赋给c,此时c中的值是1111 1010。C++中整型量是以补码形式存放的,因此,变量c的真值是-6。
又如,“short int a=65 536;”将常量65 536赋值给变量a。常量65 536是int型量(其值是216),在内存中的存储形式是:0000 0000 0000 0001 0000 0000 0000 0000。短整型变量a在内存占16个二进制位,赋值时截取65 536内存中的低16位赋给a,此时a的16个二进制位全为0,则a的值是0,这称为赋值溢出。因为65 536超过了短整型量的数值范围(-32 768~32 767),无法直接赋值给短整型量。
(2)“短的”整型量赋给“长的”整型量
“短的”整型量赋给“长的”整型量又分成两种情况。
1)将“短的”无符号整型量赋给“长的”整型变量,方法是在“短”的无符号整型量前补0,使其长度达到“长的”整型量的位数。例如:
unsigned char c = -4;
int i;
i = c;
此例中涉及两次赋值,赋值过程中各常量、变量的内存形式如下。首先将“长的”整型量-4赋给“短的”整型变量c,c获取的值是-4的内存表示形式的低8位;再将“短的”c变量的值赋给“长的”整型变量i。因为c是无符号整型量,占8位,而i是32位,此时在c的内存内容前补0使其扩展到32位后,赋值给变量i。
-4:1111 1111 1111 1111 1111 1111 1111 1100
c: 1111 1100
i:0000 0000 0000 0000 0000 0000 1111 1100
结果:变量i的值是252。
2)将“短的”有符号整型量赋给“长的”整型量。此种情况只需做符号位扩展,即在“短的”整型量前补符号位,使其长度达到“长的”整型量的长度,然后赋值。例如:
char c = -4;
int i = c;
赋值过程中各常量、变量的内存表示形式如下:
-4:1111 1111 1111 1111 1111 1111 1111 1100
c: 1111 1100
i:1111 1111 1111 1111 1111 1111 1111 1100(扩展负号)
结果:变量i的值是-4。又如:
char c = 4;
int i = c;
赋值过程中各常量、变量的内存表示形式如下:
4:0000 0000 0000 0000 0000 0000 0000 0100
c: 0000 0100
i:0000 0000 0000 0000 0000 0000 0000 0100(扩展正号)
结果:变量i的值是4。
2.5.2 各种类型运算量混合运算时的自动类型转换
C++语言中各种类型的常量和变量之间可以混合运算。例如,已知“int a=1; double b=2;”,则可进行a+b运算。两个不同类型的量运算时,计算机内部首先将它们转换成相同数据类型的量,然后进行运算。例如,上述a+b运算,计算机首先将a的值转换为double型表示,然后与double型的b的值相加。这种转换是C++内部自动完成的,编程者必须掌握转换规则,否则编程会出问题。转换规则如图2-4所示。图2-4中横向向左的箭头表示必定转换。例如,已知“char c1, c2;”,在做c1+c2运算时,首先将c1和c2的值均转换成int型表示,再将两个int型量相加。图2-4中纵向箭头表示不同数据类型混合运算时的转换方向,规则是由低类型向高类型转换,例如,上述a+b运算将低类型int值转换成高类型double值,然后运算。所谓低类型是指占用存储字节少、数据范围小的类型,所谓高类型是指占用存储字节多、数据范围大的类型。
例如,已知“int i; float f; double d;”,则表达式10+'a'+i * f - d / i的运算顺序和类型转换过程如图2-5所示。首先计算第①步,结果是int型量,再依次计算第②~⑤步,最终整个表达式的结果的类型是double型。
掌握了混合运算时数据类型的转换规则后,读者应该能理解5/2的结果为2,5.0/2的结果为2.5的道理了,参见2.4.2节。
2.5.3 强制类型转换
前面介绍了不同类型量相互赋值时以及混合运算时的自动类型转换,但有时为了强调类型的概念或者为了满足运算符对数据类型的要求,可以显式地写出类型转换,称为强制类型转换。格式是:
<类型名> (<表达式>) 或 (<类型名>) <表达式>
例如:
`int i, a;
float x, y;
double z;
i = int(x+y); 或 i = (int)(x+y);
z = double(a); 或 z = (double)a;
a = int(z) % i; 或 a = (int)z % i;`
例如,i=int (x+y)的意义是将表达式x+y的值转换为int型量,赋值给变量i。类型转换运算符的优先级较高,表达式int (z) % i中运算符int优先级较高,所以首先计算int (z),即将z的值取整,再进行%运算。注意,%运算符要求运算量为整型量,必须首先将z的值强制转换为整型量,才能计算%运算符。
注意:类型强制转换的对象是表达式的值,表达式double (a)的意义是将a的值(即表达式的值)转换成double型,而变量a自身仍然是int型变量。