【C语言】什么是数据的整型提升?整形数据在内存中又是如何存储的?一文迅速搞懂!

什么是整型提升?数据在内存是如何存储的?一文迅速搞懂!

话不多说,先上代码。

#include<stdio.h>
int main()
{
     unsigned char a=100;
     unsigned char b=200;
     unsigned char c=0;
     printf("%d,%d",a+b,c);
     return 0;
 }

相信粗心的小伙伴一眼就可以看出程序的输出:
那不就是:300和300嘛!多简单!
但是问题就在于实际输出并非如此。我在这里先不来揭晓问题的答案,让我们一步一步剖析其中原理,解开C程序中整型提升的面纱。

一、什么是整型提升?

整型提升从宏观上说是C语言的一种隐式类型转换。其意义是为了使变量在运算时能以相同精度进行。发生在 短整型(short)字符类型(char) 之间的相互运算中。

用一句话概括就是:短整型以及字符类型的变量之间或者相互进行算术运算操作时,就会发生整型提升

我知道这时候一定有人要问:
1、为什么要进行整型提升?

原因很简单,4字节长度(32比特)是CPU当中通用寄存器的一般长度,在CPU的逻辑运算单元中(ALU)通常也是以4字节长度进行运算的,因此CPU难以直接处理两个8比特的运算(这里以char类型为例)。所以在运算类整型变量使,要将内容提升至整型长度进行运算。运算完成后,在返回变量存储时,再按照原来变量类型长度进行截断。

2、那么如何进行整型提升呢?

有人说直接将8(16)比特延长成32比特(4字节)不就行了?但是还有一个问题不容忽略,那就是符号问题。在C语言中 如果不对变量类型进行表明,编译器会默认变量类型为signed(有符号)类型,只有当在变量类型前加 unsigned 时,编译器才会将其编译为无符号类型。

显然,对于有无符号的char类型变量的整型提升是不同的。

对于有符号类型的变量,整型提升时补充符号位
对于无符号类型的变量,整型提升时补0

这里举几个例子:

char a=-1;
//-1在计算机中以补码进行存储
//-1的补码是11111111,其中首位为符号位
//那么进行整型提升时,补符号位 -1——> 11111111 11111111 11111111 11111111
char b=1;
//b同样为有符号char类型变量
//b为正数,符号位为0且正数的原码与反码相同 1的补码是00000001
//有符号进行整型提升,正数符号为0,补充0
//1——> 00000000 00000000 00000000 00000001

unsigned char c=100;
//c为无符号char类型变量,整型提升时进行补0操作
//100为正数,补码与原码相同:01100100
//整型提升:00000000 000000000 00000000 01100100

经过这三个例子的介绍,基本可以掌握整型提升的方法。

然后我们来看下面这个实际例子:

int main()
{
   char c=1;
   printf("%u\n",sizeof(c));
   printf("%u\n",sizeof(!c));
   printf("%u\n",sizeof(c+));
   return 0;
}

这段代码的输出是什么?

经过验证你可能发现,输出为1,4,4 似乎与一些人想法不同(1,1,1)
输出不是1,1,1的原因就在于只要c参与了运算,那么就会被整型提升,当没有新的变量进行存储时,长度就是被提升后的4个字节。
sizeof©中c没有参与运算,结果理所当然的为1个字节
sizeof(!c)中对c进行按位取反操作,c被整型提升,c长度为4个字节
sizeof(c+)中对c没有实质性的运算改变,但是加号改变了c的存在性质,所以c的长度被提升至4个字节。

现在我们在回头来看开始那段代码:

#include<stdio.h>
int main()
{
	unsigned char a = 100;
	//无符号char 类型 100—> 01100100 正数原码反码补码相同
	//a整型提升:00000000 00000000 00000000 01100100
	unsigned char b = 200;
	//无符号char 类型 200—> 11001000
	//b整型提升:00000000 00000000 00000000 11001000
	//a整型提升:00000000 00000000 00000000 01100100
	unsigned char c = 0;
	c = a + b;
	//加之前要对char;类型进行整形提升然后计算:00000000 00000000 00000001 00101100
	printf("%d,%d\n", a+b, c);//有符号打印
    return 0;
}

这里在打印输出时对a+b, c进行了有符号 (%d) 打印,好在a,b,c均为无符号正数,在打印上不会存在“捣乱”的符号位。因此a+b应为32位完整加法下的结果:300(1 00101100,注意最左端的1不是符号位,因为a,b为无符号类型),而存在char类型中c的结果为截断后40(00101100)

二、整形数据在内存中的存储方式

相信没有系统学习过计算机组成原理的人也能知道,在计算机底层中,都是以0 1组成的二进制数据进行存储的,但是不同类型的数据,却有着不同的存储方式,本文先行介绍整型数据的存储方式。

在了解整型存储方式之前,我们还得明确哪些类型是输入整型范畴的
按照字节长短分别是:char, short, int ,long 其中包括所代表的有符号及无符号类型,以及数组。

对于一个整数来说,从计算机视角来看,其有三种存在状态,分别是这个整数的原码、反码、补码。

所谓原码就是直接转化为二进制数,而反码是原码符号位不变,其余位按位取反得到的,在反码的基础上加1就得到了补码。

那么在底层存储中,到底存储的是这个整数的哪种状态呢?

为了方便计算,计算机会以一个整数的补码进行存储。

举个例子:
做一个减法运算10-20= -10
则创建两个有符号变量a,b
a的十进制数为 10
其补码为00000000 00000000 00000000 00001010 //a
b的十进制数为-20
其原码为10000000 00000000 00000000 00010100
其反码为11111111 11111111 11111111 11101011
其补码位11111111 11111111 11111111 11101100 //b
让a与b的补码相加
11111111 11111111 11111111 11110110
以此反推回对应的十进制数恰好为-10
这说明当以补码方式进行加和运算时,会取消符号对算数结果的影响,可以统一讲运算都归纳为加法运算。

另一方面,CPU中只存在加法器,补码无疑是最有效的整型存储方式。

所以对于一个整型数据来说,在计算机中是以其补码形式存储的。但需要注意的是,对于有符号的整型数据来说来说,首位为1表示负数,首位为0表示正数。

  • 13
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JasonTuring

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值