总的来说,主要有三种位宽转换:
- 短位宽到长位宽
- 长位宽到短位宽
- 同位宽转换
短位宽扩展到长位宽
基本原则
- 有符号数的扩展
- 不管是扩展成有符号还是无符号数,通通按符号位扩展。
- 无符号数的扩展
- 不管是扩展成有符号还是无符号数,通通按零扩展。
- 简而言之,无符号数扩展,前面全填0;有符号数扩展,按符号位扩展,若为负,前面全填1,若为正,前面全填0。
举例说明
将8位有符号数signed char扩展成16位有符号数short,举例如:
- 8位有符号数:
-128, 1000 0000
- 转16位有符号:
-128, 1111 1111 1000 0000
- 过程
- 数值:-128
- 先取绝对值:0000 0000 1000 0000
- 取反:1111 1111 0111 1111
- 加一:0000 0000 1000 0000
- 总结
- 口诀:若为负数,则前置全扩展为1,若为非负数,则前置全扩展为0.
- 核心:从低往高转换,对外表现的值不变。
将8位有符号数signed char扩展成16位无符号数unsigned short,举例如:
- 8位有符号数:
-128, 1000 0000
- 转16位无符号数为:
65408, 1111 1111 1000 0000
- 过程:统一按有符号数往高位扩展,然后按无符号数解析。
- 二进制本身与上一种情况一样,但是按无符号数去解析。
再比如8位的有符号数:-1(1111 1111)
,扩展成16位:1111 1111 1111 1111
,具体可以按需求做无符号(65535)、有符号数(-1)解析。验证代码如下:
signed char a = -1;
short b = a;
printf("%hd, 0x%hx, %hd, 0x%hx \n", a, a, b, b);
unsigned short c = a;
printf("%hd, 0x%hx, %hu, 0x%hx \n", a, a, c, c);
将8位无符号数unsigned char扩展成16位有符号数short,举例如:
- 8位无符号数:
128, 1000 0000
- 转16位有符号:
128, 0000 0000 1000 0000
- 总结:无符号数往宽数据类型扩展,高位全填零,再按对应类型解析。
本质是对计算机存储的补码进行操作,如8位的-1补码,扩展成16位-1补码,然后赋值,至于是按有符号还是无符号解析,是由扩展后赋值的量来决定。
长位宽扩展到短位宽
基本原则
直接取长位宽的相应位宽的低位字节数据赋值给短位宽类型,然后再按短位宽具体有符号、无符号数据类型解析。
举例说明
尝试将64位转到32位数据:
- 例1
- 转换前,int64_t:
-1, 0xffffffffffffffff
- 转换成,int32_t:
-1, 0xffffffff
- 转换成,uint32_t:
4294967295, 0xffffffff
- 转换成,int16_t:
-1, 0xffff
- 转换成,uint16_t:
65535, 0xffff
- 转换前,int64_t:
- 例2
- 转换前,uint64_t:
1, 0x1
- 转换成,int32_t:
1, 0x1
- 转换成,uint32_t:
1, 0x1
- 转换成,int16_t:
1, 0x1
- 转换成,uint16_t:
1, 0x1
- 转换前,uint64_t:
- 例3
- 转换前,uint64_t:
2147483648, 0x80000000
- 转换成,int32_t:
-2147483648, 0x80000000
- 转换成,uint32_t:
2147483648, 0x80000000
- 转换成,int16_t:
0, 0x0000
- 转换成,uint16_t:
0, 0x0000
- 转换前,uint64_t:
验证代码如下:
uint64_t a = -1;
int32_t b = a;
printf("%lld, 0x%llx, %d, 0x%x \n", a, a, b, b);
uint32_t c = a;
printf("%lld, 0x%llx, %u, 0x%x \n", a, a, c, c);
int16_t d = a;
printf("%lld, 0x%llx, %hd, 0x%hx \n", a, a, d, d);
uint16_t e = a;
printf("%lld, 0x%llx, %hu, 0x%hx \n", a, a, e, e);
从上例不难看出本质是取的计算机存储的补码中,低位字节对应位宽数据。
同位宽转换
基本原则
只是解析方式不同,本质存储的补码一样。
举例说明
尝试将32位数据无符号有符号数相互转换,验证代码如下:
int32_t a = -1;
uint32_t b = 1000;
b = a;
printf("%hd, 0x%hx, %hu, 0x%hx \n", a, a, b, b);
b = 1000;
a = b;
printf("%hd, 0x%hx, %hu, 0x%hx \n", a, a, b, b);
b = 2147483647;
a = b;
printf("%hd, 0x%hx, %hu, 0x%hx \n", a, a, b, b);
输出结果为:
-1, 0xffff, 65535, 0xffff
1000, 0x3e8, 1000, 0x3e8
0, 0x0, 0, 0x0
很容易看出,同位宽赋值类型转换时,本质存的二进制补码都相同,只是按有符号和无符号方式去进行解析。