C学习:不同位宽整数扩展问题分析

C学习:不同位宽整数扩展问题分析

总的来说,主要有三种位宽转换:

  • 短位宽到长位宽
  • 长位宽到短位宽
  • 同位宽转换

短位宽扩展到长位宽


基本原则

  • 有符号数的扩展
    • 不管是扩展成有符号还是无符号数,通通按符号位扩展。
  • 无符号数的扩展
    • 不管是扩展成有符号还是无符号数,通通按零扩展。
  • 简而言之,无符号数扩展,前面全填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
  • 例2
    • 转换前,uint64_t:1, 0x1
    • 转换成,int32_t:1, 0x1
    • 转换成,uint32_t:1, 0x1
    • 转换成,int16_t:1, 0x1
    • 转换成,uint16_t:1, 0x1
  • 例3
    • 转换前,uint64_t:2147483648, 0x80000000
    • 转换成,int32_t:-2147483648, 0x80000000
    • 转换成,uint32_t:2147483648, 0x80000000
    • 转换成,int16_t:0, 0x0000
    • 转换成,uint16_t:0, 0x0000

验证代码如下:

    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

很容易看出,同位宽赋值类型转换时,本质存的二进制补码都相同,只是按有符号和无符号方式去进行解析。

猜你喜欢

转载自blog.csdn.net/qq_17256689/article/details/129938851
今日推荐