类型转换和缩减
转换的三种情况
一、短数据类型扩展为长数据类型
要扩展的短数据类型为有符号数的 进行符号扩展,即短数据类型的符号位填充到长数据类型的高字节位(即比短数据类型多出的那一部分),保证扩展后的数值大小不变
char x=10001001b; short y=x; 则y的值应为11111111 10001001b;
char x=00001001b; short y=x; 则y的值应为00000000 00001001b;
要扩展的短数据类型为无符号数的 进行零扩展,即用零来填充长数据类型的高字节位
unsigned char x=10001001b; short y=x; 则y的值应为00000000 10001001b;
unsigned char x=00001001b; short y=x; 则y的值应为00000000 00001001b;
二、长数据类型缩减为短数据类型
如果长数据类型的高字节全为1或全为0,则会直接截取低字节赋给短数据类型;
如果长数据类型的高字节不全为1或不全为0,则转会就会发生错误。
三、同长度的数据类型中有符号数与无符号数的相互转化
直接将内存中的数据赋给要转化的类型,数值大小则会发生变化。
短类型扩展为长类型时,但短类型与长类型分属有符号数与无符号数时,则先按规则一进行类型的扩展,再按本规则直接将内存中的数值原封不动的赋给对方。
转换表
有符号数的转换 | ||
---|---|---|
从 | 到 | 方法 |
char | short | 符号位扩展 |
char | long | 符号位扩展 |
char | unsigned char | 最高位失去符号位意义,变为数据位 |
char | unsigned short | 符号位扩展到short;然后从short转到 unsigned short |
char | unsigned long | 符号位扩展到long; 然后从long 转到unsigned long |
char | float | 符号位扩展到long; 然后从long 转到float |
char | double | 符号位扩展到long; 然后从long 转到double |
char | long double | 符号位扩展到long; 然后从long 转到long double |
short | char | 保留低位字节 |
short | long | 符号位扩展 |
short | unsigned char | 保留低位字节 |
short | unsigned short | 最高位失去符号位意义,变为数据位 |
short | unsigned long | 符号位扩展到long; 然后从long转到unsigned double |
short | float | 符号位扩展到long; 然后从long 转到float |
short | double | 符号位扩展到long; 然后从long 转到double |
short | long double | 符号位扩展到long; 然后从long 转到double |
long | char | 保留低位字节 |
long | short | 保留低位字节 |
long | unsigned char | 保留低位字节 |
long | unsigned short | 保留低位字节 |
long | unsigned long | 最高位失去符号位意义,变为数据位 |
long | Float | 使用单精度浮点数表示。可能丢失精度。 |
long | double | 使用双精度浮点数表示。可能丢失精度。 |
long | long double | 使用双精度浮点数表示。可能丢失精度。 |
无符号数的转换 | ||
---|---|---|
从 | 到 | 方法 |
unsigned char | char | 最高位作为符号位 |
unsigned char | short | 0扩展 |
unsigned char | long | 0扩展 |
unsigned char | unsigned short | 0扩展 |
unsigned char | unsigned long | 0扩展 |
unsigned char | float | 转换到long; 再从 long 转换到float |
unsigned char | double | 转换到long; 再从 long 转换到double |
unsigned char | long double | 转换到long; 再从 long 转换到double |
unsigned short | char | 保留低位字节 |
unsigned short | short | 最高位作为符号位 |
unsigned short | long | 0扩展 |
unsigned short | unsigned char | 保留低位字节 |
unsigned short | unsigned long | 0扩展 |
unsigned short | float | 转换到long; 再从 long 转换到float |
unsigned short | double | 转换到long; 再从 long 转换到double |
unsigned short | long double | 转换到long; 再从 long 转换到double |
unsigned long | char | 保留低位字节 |
unsigned long | short | 保留低位字节 |
unsigned long | long | 最高位作为符号位 |
unsigned long | unsigned char | 保留低位字节 |
unsigned long | unsigned short | 保留低位字节 |
unsigned long | float | 转换到long; 再从 long 转换到float |
unsigned long | double | Convert directly to double |
unsigned long | long double | 转换到long; 再从 long 转换到double |
深奥
进制补码系统中,同一个负数在不同大小的表示法中的表示是不同的。你不能在一个包含16位数的表达式中随意地使用8位有符号数,转换是必需的。这种转换,以及其逆操作(将16位数转换为8位)就是符号扩展(sign extension)与缩减(contraction)操作。
个数从某个位数符号扩展到一个更大的位数很简单,只需要将符号位复制到新格式新增的高端各位即可
例如,为了将一个8位的数符号扩展到16位,只需将8位数的第7位复制到16位数的第8 .. 15位即可。而将一个16位数符号扩展到一个双字,只需要将第15位复制到双字的第16 .. 31位即可。
处理不同长度有符号数的时候,必须使用符号扩展。例如,在将一个字节量与一个字量相加的时候,在相加之前必须将字节量符号扩展到16位。其他运算可能又会需要符号扩展到32位。
处理无符号二进制数的时候,可以使用零扩展(zero extension)来将小位数的无符号数扩展到大位数的无符号数。零扩展非常简单——只需要用零来填充大位数操作数的高端各个字节即可。大多数高级语言编译器会自动处理符号扩展与零扩展、
语言(例如Ada)在从小数据类型转换到大数据类型时需要显式转换(explicit cast)。查一下所用语言的参考手册就知道这种显式转换是不是必需的了。要求提供显式转换的语言的优点在于编译器永远不会在程序员不知情的情况下做任何事情。如果你没有提供必要的转换,编译器会给出一个诊断消息,让你知道程序还需要改进。
符号扩展和零扩展,有一点需要明确的是,它们是需要付出代价的。将一个小整型赋值给一个大整型可能会比在同样大小的整型变量间传输数据需要更多的机器指令(执行时间更长)。因此,在一个数学表达式或者一条赋值语句中混合使用不同大小的变量要小心。
符号缩减,即将一个某位数转换为值相同但位数变小的数,比较麻烦。符号扩展永远不会失败,使用符号扩展,一个m位有符号数永远可以转换为一个n位数(这里n>m)。不幸的是,在m<n的情况下,一个n位数不是总能转换为m位数。例如,-448的16位十六进制表示是$FE40,而这个数的大小对于8位来说太大了,我们无法将其符号缩减到8位。
将一个数值正确地符号缩减,必须要检查需要丢弃的高端字节。首先,这些高端字节必须是全零或者$FF,如果它们包含其他值,我们就无法对这个数进行符号缩减。其次,最终结果的最高位必须与被丢弃的所有位一致。