【C语言】整型提升和类型转换

要理解整形提升类型转换的话首先要理解计算机的原码、反码、补码

1.原码

计算机存储数据是用二进制数存储的。
把一个整数转换成二进制形式就是原码,原码最左边的一位数表示符号位,0为正,1为负
例如:int a = 4; 那么a的原码就是00000000 00000000 00000000 00000100
例如:int b = -4; 那么b的原码就是10000000 00000000 00000000 00000100

2.反码

正数的原码、反码、补码相同,负数的补码就是除了符号位,其他所有位取反
例如:int a = 4; 那么a的反码就是00000000 00000000 00000000 00000100
例如:int b = -4; 那么b的反码就是11111111 11111111 11111111 11111011

3.补码

正数的原码、反码、补码相同, 负数的补码就是反码+1
例如:int a = 4; 那么a的补码就是00000000 00000000 00000000 00000100
例如:int b = -4; 那么b的补码就是11111111 11111111 11111111 11111100
计算机中的数据都是以补码存储的,如果是正数的话,原码就是其补码,如果是负数的话,就要转换成补码

  • 正数的原、反、补码都相同
  • 负数的原、反、补码各不相同

4.整型提升和类型转换

整型提升是什么?

在进行表达式运算时,所有值都要先提升成int类型,因为运算会在CPU相应的运算器件内执行,而CPU的整型运算器的操作数的字节长度一般是4个字节,也就是int类型的字节长度。
所以如果是char或者short类型的变量,在CPU的运算器件中是很难计算的,所以会先整型提升到4个字节再进计算
整型提升是按照数据的符号位来提升的,正数的符号位为0,所以高位补0,负数的符号位为1,所以高位补1

分析以下代码在底层是怎么运行的
例1:

int main(){
	char a = 3;
	char b = 127;
	char c = a + b;
	
	printf("%d\n",c);

	return 0;
}

首先把3这个整型赋值给char类型的a
3这个整型的原码是:
00000000 00000000 00000000 00000011
因为正数的原、反、补相同,所以补码也是:
00000000 00000000 00000000 00000011
因为整型变量是4个字节,而字符型变量只有1个字节,所以把整型值赋值给a会发生截断
所以a变量里面存储的就是3的补码的最后八位:
00000011
127这个整型的补码是:
00000000 00000000 00000000 01111111
赋值给b变量后,b变量里存储的就是:
01111111
把 a+b 的值赋值给c,这里在进行表达式运算,而且a和b都是char类型的,都没有达到一个int大小,所以会发生整形提升,a和b都为正数,高位补0
所以就是:
00000000 00000000 00000000 00000011 加上 00000000 00000000 00000000 01111111
结果是:00000000 00000000 00000000 10000010
然后赋值给char类型的c会发生截断,只取最后八位,那么c里存储的就是:
10000010
printf("%d\n",c); %d就是以有符号整型的形式打印
以整型的形式打印,c就会先提升成4个字节,高位补符号位,所以c是:
11111111 11111111 11111111 10000010 - 补码
又因为计算机底层存储的是补码,而我们看到的应该是原码,所以这里输出就要转换成原码输出
反码:
11111111 11111111 11111111 10000001 - 反码
原码:
10000000 00000000 00000000 01111110 - 原码
所以输出的结果就是:-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;
}

0x或者0X开头的数据是十六进制的数,b6(16)转换成十进制数就是 11 * 161 + 6 * 160 = 182(10)
182这个整型的补码是:
00000000 00000000 00000000 10110110
赋值给a发生截断,所以a里存储的就是:
10110110
if(a == 0xb6),这里在进行表达式运算,会发生整型提升,a的符号位为1,高位补1
所以a是:
11111111 11111111 11111111 10110110 - 补码
转换成原码
11111111 11111111 11111111 10010101 - 反码
10000000 00000000 00000000 01101010 - 原码
所以if(a == 0xb6)这里的a就是106,0xb6转换成十进制是182
106 == 182 是错的,所以不会输出a
因为char类型的a不足4个字节,运算时会发生整型提升,值就有可能被改变
b同理,所以b也不会输出

可以看到,a和b都发生了整型提升,但是b6000000一共占用4个字节刚好可以存储在c里,并且在 if(c == 0xb6000000) 比较时,c就是4个字节,所以c不会发生整型提升,所以c里的值就不会改变,所以这里是对的,就会输出c

总结:
有符号char类型的a变量占用1个字节,不足4个字节,在进行运算时会发生整形提升,值就有可能被改变
有符号short类型的b变量占用2个字节,不足4个字节,在在进行运算时会发生整形提升,值就有可能被改变
有符号int类型的c变量本来就是一个整型,占用4个字节,所以在进行运算时不会发生整形提升,值就不会被改变

例3:

int main(){
	char c = 1;
	printf("%d\n",sizeof(c)); 
	printf("%d\n",sizeof(+c)); 
	printf("%d\n",sizeof(-c)); 
	printf("%d\n",sizeof(!c)); 

	return 0;
}

先看结果
在这里插入图片描述

第一个printf没有进行计算,就没有发生整型提升,所以还是1个字节
第二个printf有计算,发生整型提升,所以是4个字节
第三个printf有计算,发生整型提升,所以是4个字节
第四个printf有计算,发生整型提升,所以应该是4个字节,但是因为编译器不同,这里vs编译器输出的是1,gcc编译器会输出4。

以上都是隐式类型转换

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值