C语言学习--代码分析整形提升过程

整型提升

在C语言中,各种整形类型的运算要首先提升为int类型,再进行计算。如果接收运算结果的变量为short或者char则会发生数据截断。

为什么要整形提升

因为表达式在的整形运算实在CPU的运算器内执行,CPU整形运算器(ALU)的操作数字节长度一般与int的字节长度一样。
因此,表达式中的char类型和short类型在运算时会被转换为int,这种转换称为整型提升
同时,在整形提升时,一般会提升为signed int类型,当signed int装不下时,则会提升为unsigned int类型。
比如,在C语言中规定了整形的长度 char≤short≤int,如果unsigned short的长度等于int,则unsigned short会被转换为unsigned int

整型提升的方式

整型提升是按照变量的数据类型的符号位来提升

负数的整型提升,高位补符号位1

char c1 = -1;
// c1 的二进制补码为:
// 1111 1111
// 整型提升,高位补符号位:
// 1111 1111 1111 1111 1111 1111 1111 1111

正数的整型提升,高位补符号位0

char c2 = 1;
// c2 的二进制补码为:
// 0000 0001
// 整型提升,高位补符号位:
// 0000 0000 0000 0000 0000 0000 0000 0001

无符号数整型提升,高位补0

//无符号整形提升,高位补0
unsigned char c3 = 1;
// c2 的二进制补码为:
// 0000 0001
// 整型提升,高位补符号位:
// 0000 0000 0000 0000 0000 0000 0000 0001

代码分析

例1

int main()
{
    char a = 3;
    char b = 127;
    char c = a + b;  
    printf("%d\n",c);  // -126
    return 0;
// b 和 c 运算过程中先被提升为int类型,然后再执行加法运算。
// 加法运算完成后,结果将被截断,然后再存储于a中。
// a + b = 130,对应2进制表示为:
// 0000 0000 0000 0000 0000 0000 1000 0010 
// 将值赋值给c,会将溢出的部分截断,得到结果:
// 1000 0010
// char 默认是 signed char ,最高位是符号位,所以此时的c 是负数,并且得到的是补码。
// 以%d格式打印整型,因此c又需要整型提升
// 补码 1111 1111 1111 1111 1111 1111 1000 0010
// 反码 1111 1111 1111 1111 1111 1111 1000 0001
// 原码 1000 0000 0000 0000 0000 0000 1111 1110 
// 结果 == -126
}

例2

// 下面代码的执行结果是?
int main()
{
	char a = 0xb6;
	short b = 0xb600;
	int c = 0xb6000000;
	if (a == 0xb6)
		printf("a");
	if (b == 0xb600)
		printf("b");
	if (c == 0xb6000000)
		printf("c");
	return 0;
}

逐步分析

  1. 首先abc在被赋值时,=后面的值默认为signed int类型;

    所以,0xb6 == 182 == 0000 0000 0000 0000 0000 0000 1011 0110

    asigned char类型,只有8位,最高位为符号位,因此a在接收值时要发生数据截断;

    得到:

    1011 0110 ,此时的值最高位为1是一个负数值,并且是一个补码,我们将其变成原码;

    a 1011 0110
    a 1011 0101
    a 1100 1010

    所以a == -74在这里插入图片描述

  2. b 在被赋值时同理:

    0xb600 == 46592== 0000 0000 0000 0000 1011 0110 0000 0000

    截断:

    b 1011 0110 0000 0000

    b 1011 0101 1111 1111

    b 1100 1010 0000 0000

在这里插入图片描述

  1. 0xb6000000 == 3053453312 == 01011 0110 0000 0000 0000 0000 0000 0000

    因为是有符号数,但是int类型又没有空间装下这个最高位的0

    因此发生截断,最高位0被丢弃,1作为符号位,此时的值为负数,得到:

    c 1011 0110 0000 0000 0000 0000 0000 0000

    c 1011 0101 1111 1111 1111 1111 1111 1111

    c 1100 1010 0000 0000 0000 0000 0000 0000

    所以在截断后:

    0xb6000000 --> -1241513984 == 1011 0110 0000 0000 0000 0000 0000 0000 (补)

    c同样是unsigned int, 刚好可以放下这32位二进制数,所以:

    c == -1241513984 == 1011 0110 0000 0000 0000 0000 0000 0000 (补)

    这里就可以发现c0xb6000000是相同的。

在这里插入图片描述

  1. 当算出 a == -74, b == -18944, c == -1241513984后,继续进行条件判断,在if() 判断时,两边a,b 要被整形提示。

    if (a == 0xb6)判断的是:

    a -- 1111 1111 1111 1111 1111 1111 1011 0110 (a被整形提升)

    0xb6 -- 0000 0000 0000 0000 0000 0000 1011 0110

    可以看到(a == 0xb6) == false

  2. if(b == 0xb600)判断的是:

    b -- 1111 1111 1111 1111 1011 0110 0000 0000 (b被整形提升)

    0xb600 -- 0000 0000 0000 0000 1011 0110 0000 0000

    可以看到(b == 0xb600) == false

  3. if(c == 0xb6000000)判断的是:

    c -- 1011 0110 0000 0000 0000 0000 0000 0000 (c本身就是int类型)

    0xb6000000 -- 1011 0110 0000 0000 0000 0000 0000 0000

    可以看到(b == 0xb600) == true

因此,第三个if(c == 0xb6000000)被执行,打印输出a。

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值