在C语言代码中我们经常会遇到对变量进行类型强转,如果没有深入理解类型强转,很容易引入代码bug,比如把int类型强转成char就有可能会截断数据,后面代码流程会造成意想不到的错误。这里将会总结一下C语言里的类型强转,建议在安全的前提下进行类型转换。
一:符号扩展和零扩展
在C语言中每种类型都有相应的字节数,比如char是1个字节,short是2个字节,那从1个字节转成2个字节,多出来的一个字节应该填什么。大部分同学可能一开始说用0填充,其实这是需要分情况的,详细如下:
1,符号扩展:对于要扩展量为有符号数,扩展存储位数的方法。在新的高位字节使用当前最高有效位即符号位的值进行填充
char a=0xff;//有符号值为-1,二进制为11111111,其中最高位为符号位
short b=a;//b的有符号值为-1,二进制为1111111111111111
-----
char a=1;//有符号值为-,二进制为00000001,其中最高位为符号位
short b=a;//b的有符号值为1,二进制为0000000000000001
2,零扩展:对于要扩展量为无符号数,扩展存储位数的方法。在新的高位字节用0填充
unsigned char a=0xff;//二进制为11111111,所有值都是有效值
unsigned short b=a;//b经过零扩展后,内存中存储的值为0000000011111111
总结:若要扩展的量为有符号量,不管扩展成有符号还是无符号,都遵循符号扩展;若要扩展的为无符号量,不管扩展成有符号还是无符号,都遵循零扩展。
例:
char a=0xff;//a=-1,其为有符号量,二进制为11111111
unsigned short b=a;//此处a要进行符号扩展,b的二进制为1111111111111111
---------
unsigned char a=0xff;//a=255,为无符号量,二进制为11111111
short b=a;//此处a要进行零扩展,b的二进制为0000000011111111
二:从有符号类型到其他类型转换合集
从 |
到 | 方法 |
---|---|---|
char | short | 符号位扩展 |
char | long | 符号位扩展 |
char | unsigned char | 最高位失去符号位意义,变为数据位 |
char | unsigned short | 符号位扩展到short,然后从short转换为unsigned short |
char | unsigned long | 符号位扩展到long,然后从long转换为unsigned long |
char | float | 符号位扩展到long,然后转到double |
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 |
char |
保留低位字节 |
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 |
直接转换成double |
unsigned long |
long double |
转换到long; 再从 long 转换到double |
四:总结
-
char/short/uchar/ushort任意的混合运算,结果类型为int
-
char/short与uchar/ushort进行大小比较运算时,有符号数符号扩展为int类型,无符号数按照0扩展为int类型。最终按照int比较
-
char/short/int/uchar/ushort与uint进行大小比较运算时,转化为uint类型的比较
-
char/short/int/uchar/ushort与ulong进行大小比较运算时,转化为ulong类型比较
-
无符号数之间的大小比较时,仍按照无符号比较
-
有符号数之间的大小比较时,按照有符号比较