算术转换与整形提升

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

算术转换

  C语言在处理不同类型数值之间的运算时是有一定的规律的。需要先将两个操作数转换为相同的类型才能进行运算。而类型的转换的规律如下图:
  

  • 这里的转换是自动由低向高发生的(当然,强制类型转换是根据用户意愿进行的)。例如:int和unsigned int进行运算,编译器会将低级别的int转换为unsigned int再进行计算。而这个转换编译器并没有对它在内存中的值做出改变,而是使用了不同的读取方式,编译器将原本的int的符号位也当成数值大小进行读取。
  • 而这里没有提到的char和unsigned char,short和unsigned short类型在运算时都会自动为‘升级’为int型再进行运算。也就是整形提升

整形提升

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

了解清楚概念后,在来看原题:

    char u = 128;
    unsigned char s = 128;
    unsigned short us;
    us = s + u;
    printf("us = 0x%x\n", us);
  • 128的补码是00000000 00000000 00000000 10000000
  • usigned char型(-128–127)的,将128放到u时截断,u10000000,即-128。同理,unsigned char型(0–255)的s128
  • 当进行s+u算数运行时,先进行整形提升。此时u-128负数,所以前32位补1,即 11111111 11111111 11111111 10000000;s128正数,所以前32补0,即 00000000 00000000 00000000 10000000
  • s和u的值相加得
    00000000 00000000 00000000 10000000   //s的补码  无符号相当于正数,原反补一样,提升为整型时,高位补0,
    11111111 11111111 11111111 10000000   //u提升为整型的补码 u是signed char
+   -----------------------------------
 [1]00000000 00000000 00000000 00000000

又因为usunsigned short型,进行截断,即00000000 00000000,故us=0

    us = (char)s + u;
    printf("us = 0x%x\n", us);

s强转换成char型,s10000000,即-128;与u相加先整形提升,即

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

在进行截断赋值给us,即11111111 00000000,为ff00

    us = (unsigned char)u + s;
    printf("us = 0x%x\n", us);

同理,就不阐述了,算出来us为0000000100000000,即100;

程序最后验证结果:

猜你喜欢

转载自blog.csdn.net/sifanchao/article/details/80379869