【C语言】算术转换与整形提升

算术转换与整形提升

  就在前天,我做了一道这样的题,它使我发现我对数值类型转换这里的知识很肤浅。所以我整理了一下这方面的知识。
  下面我做测试的平台是VS 2013 32位环境(小端字节序)。
  这是原题:  

int main()
{
    char u = 128;
    unsigned char s = 128;
    unsigned short us;
    us = s + u;
    printf("us = 0x%x\n", us);
    us = (char)s + u;
    printf("us = 0x%x\n", us);
    us = (unsigned char)u + s;
    printf("us = 0x%x\n", us);
    return 0;
}

算术转换

  C语言在处理不同类型数值之间的运算时是有一定的规律的。需要先将两个操作数转换为相同的类型才能进行运算。而类型的转换的规律如下图:
  int
  unsigned int
  long int
  unsigned long int
  float
  double
  long double
  这里写图片描述
  这里的转换是自动由低向高发生的(当然,强制类型转换是根据用户意愿进行的),例如:intunsigned int进行运算,编译器会将低级别的int转换为unsigned int再进行计算。而这个转换编译器并没有对它在内存中的值做出改变,而是使用了不同的读取方式,编译器将原本的int的符号位也当成数值大小进行读取。。
  而这里没有提到的charunsigned charshortunsigned short类型在运算时都会自动为‘升级’为int型再进行运算。也就是我们所说的整形提升
  

整形提升

  相应的,不同的低级别的类型向高级别类型整形提升的过程也是不太一样的。
    
  这里的转换的规律是:
  unsigned char在转化时,编译器会将他们当成正数进行转化,在高位补0,补全后就是它的补码
  signed char转化时,编译器则会根据他们的正负将他们的高位全部补0或补1,补全后就是它的补码
  我们再返回来看开头我遇到的那个题:

int main()
{
    char u = 128;
    unsigned char s = 128;
    unsigned short us;
    us = s + u;
    printf("us = 0x%x\n", us);
    return 0;
}

  usigned char型的,在与类型为unsigned char型的s进行加法运算时需要进行类型提升,提升为int型,
  因为在u进行初始化时,将128赋值给了u,而signed char的取值范围是-128 ~ 127,这里的127的原码是0111 1111,加一就是1000 0000,也就是-128,所以其实在u中存放的是-128这个数。-128的补码也是1000 0000
  那么在类型提升时,编译器会将它当作负数进行补全,高位补1,它在内存中即是0xffff80
  而sunsigned char型的,在提升时,编译器认为它是正数,所以高位补0,它在内存中为0x000080

    00000000 00000000 00000000 10000000   //s的补码  无符号相当于正数,原反补一样,提升为整型时,高位补0,
    11111111 11111111 11111111 10000000   //u提升为整型的补码 u是signed char
+   -----------------------------------
    10000000 00000000 00000000 00000000

  它俩相加后,结果为:0x80000000,在赋值unsigned shortus时将结果的低位两个字节(16位)截断赋值给us,所以us中保存的是0x0000
  再看下面两个语句:

int main()
{
    char u = 128;
    unsigned char s = 128;
    unsigned short us;
    us = (char)s + u;
    printf("us = 0x%x\n", us);
    return 0;
}

  这里将s先强制类型转换为signed char型,再进行运算。
  而s一旦转换为signed char型,它的最高位就会表示符号位,其表示的值就会变为-128,在提升为整型时与u就有了相同的待遇。
  所以这里us的补码都为0xffff80,它俩的相加结果如下:

    11111111 11111111 11111111 10000000   //u提升为整型的补码 u是signed char
    11111111 11111111 11111111 10000000   //s被强制类型转换后,与u有了相同的待遇
+   -----------------------------------
    11111111 11111111 11111111 00000000

  最终编译器将相加结果截取低位的16位(两个字节)存放到了unsigned short型的us中。这时us中存放的值是0xff00
  最后我们再看剩下两条语句:

int main()
{
    char u = 128;
    unsigned char s = 128;
    unsigned short us;
    us = (unsigned char)u + s;
    printf("us = 0x%x\n", us);
    return 0;
}

  先将u强制类型转换为unsigned char,此时u的最高位符号位变为数值大小,u的值变为128,进行整型提升时,u被编译器当作正数,高位补0,提升后,u在内存中表示为0x000080
  同样的s类型为unsigned char,整型提升后在内存中表示为0x000080,两者相加:

    00000000 00000000 00000000 10000000  //u强制类型转换为unsigned char类型后整型提升
    00000000 00000000 00000000 10000000  //s作为unsigned char类型的整型提升
+   -----------------------------------
    00000000 00000000 00000001 00000000  

  最终编译器将相加结果截取低位的16位(两个字节)存放到了unsigned short型的us中。这时us中存放的值是0x0100
  我们通过在vs2013下运行这段代码查看最终结果如下:
  这里写图片描述



如果我的文章里的解答有问题,希望小伙伴们积极指出

全文完,感谢浏览

猜你喜欢

转载自blog.csdn.net/qq_41866437/article/details/80311495