我们知道一个变量在内存中存储是要开辟一块内存空间来存储的,那么该为这个变量开辟多大的内存空间呢?这个要依据变量的类型,我们知道int类型的变量大小是4个字节,char类型的变量大小是1个字节,创建一个变量时,根据其类型来为变量申请对应大小的空间。
问题:那么不同类型的数据在内存中到底是如何存储的呢?
int a=10;//创建一个int类型的变量a,初始化为10,将其存储于内存中。
我们知道存储变量a到内存中会申请4个字节的空间。那么申请到空间以后又是如何存储的呢?
计算机底层处理时只能识别01代码,所以存入内存的数据在进行处理时也是以二进制形式来处理的,(讲解时以有符号数为例)只不过其存在不同的形式,即原码,反码,补码。
概念引入:
计算机中的有符号数有三种表示方法,即原码、反码和补码。三种表示方法均有符号位和数值位两部分,符号位都是用0表示“正”,用1表示“负”,而数值三种表示方法各不相同。
原码、反码、补码
原码:
将数值按照正负数形式表示为二进制形式即可
反码:
正数的反码与原码相同,负数在原码的基础上,符号位不变,其余位按位取反得到反码
补码:
正数的补码与原码、反码相同,负数在补码的基础上最低位加一得到补码
对于整型数据来说,在内存中存储的其实是以补码形式存储的。
我们来看一张图片:
定义了一个有符号整型变量a=-10;
内存监视窗口:
通过对内存的监视(以十六进制展示,4位二进制代表一位16进制 ),我们可以看到,a的补码的16进制为0xff ff ff f6,该整形数值在内存中确实存入了其补码(存入的是0x f6 ff ff ff,这个与大小端有关,在此不展开讲解)。
为什么是以补码形式存在内存中呢?在此简单补充一下
在计算机系统中,整型数值一律用补码来表示、存储、运算。是因为用补码可以将符号位和数值位统一处理。并且,补码与原码的相互转换的运算过程相同,无需额外的硬件电路。
整型数据包括int(signed int、unsigned int)、short(signed short、unsigned short)、long int(signed long int、unsigned long int)、long long(signed long long、unsigned long long)、char(signed char、unsigned char)
- signed 表示有符号类型
- unsigned 表示无符号类型
所以以上整型数据在内存中的存储和运算均是以二进制补码形式完成的。
PS:其中为什么字符类型也属于整型数据呢?是因为每一个字符存储都对应着一个ascii码值,ascii码值是整数类型,所以字符的存储可以理解为整数的存储,所以把char类型也归结为整型数据。
那我们再以整型数据中有符号char类型变量存储为例:
先看一张图片:
按照我们前面所讲,char类型也属于整形数据,所以在内存中存储时应该存入补码形式,但是通过对内存的监视,可以看到只有低位的8个bit位被存入内存,这是为什么呢?
这是因为-3是一个signed int类型的数据,大小为4byte,我们要把其存入到大小为1byte的char类型变量中,有一部分存不下,所以发生了截断,只保留低位。
那么如果要进行算数运算计算机是如何处理的呢?
来看一段代码
#include <stdio.h>
int main()
{
char a = -3;
//原 10000000 00000000 00000000 00000011
//反 11111111 11111111 11111111 11111100
//补 11111111 11111111 11111111 11111101
//补码16进制 0xff ff ff fd
char b = 1;
//原/反/补 00000000 00000000 00000000 00000001
//补码16进制 0x 00 00 00 01
char c = a + b;
printf("%d %d", c, a + b);
return 0;
}
通过前面的分析我们可以得出把int类型的数据存入char类型变量,会发生截断,存储低8位bit位到char变量中,那么在发生整型算数运算时,计算机又是如何处理的呢?
此处我们引入整型提升的概念。
C的整型算术运算总是至少以缺省整型类型的精度来进行的。
为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整型,这种转换称为整型提升。
通俗来讲,就是整型中的char、short类型在进行算数运算前,会被转为普通整型再进行算数运算。
整型提升规则:
- 首先提升时参照的是数据原来的类型,如果被提升的变量是无符号字符型/无符号短整型,那么在进行整型提升时,在其补码高位补0到共32个bit位。
- 如果被提升的变量是有符号短整型/有符号字符型,则根据其符号补足补码高位,再进行运算。
那么前面对char类型变量a+b的运算通过分析可得到:
计算完成后,我们以不同的形式对a+b的形式进行打印(打印时打印的是原码形式对应的值,对于负数要把其变回原码形式)
printf("%d\n", a + b);
printf("%d\n", c);
printf("%u\n", c);
代码运行结果如下图示:
为什么相同的计算过程但是打印出的值却不同呢?
打印其实实质上是反映计算机对某个数值的看待方式,同一个数看待方式不同自然打印出的结果就不同了。
让我们来逐个分析:
1)
printf("%d\n", a + b);
此种情况下,a和b整型提升后,以补码形式运算,得到计算结果,以有符号int类型打印,打印时打印数据对应的原码的值,a+b运算结果<0,将其变为原码形式打印,为-2。
2)
printf("%d\n", c);
此种情况下,a和b整型提升后,以补码形式运算,得到计算结果,将计算结果存在char类型变量c中,发生截断,以有符号int类型打印,再发生整型提升,c<0,将其变为原码形式打印,为-2。
3)
printf("%u\n", c);
此种情况下,a和b整型提升后,以补码形式运算,得到计算结果,将计算结果存在char类型变量c中,发生截断,以无符号int类型打印,前面提到,打印是计算机以不同角度看待数据的结果,以无符号整数类型打印,那么计算机处理整型提升后c的补码时,就会认为c是一个无符号类型整型变量,那么对于无符号类型变量,可以将其理解为恒正值,所以其补码就是原码,所以会打印一个很大的数,即
总结:
以不同类型打印同一数值,是计算机以不同角度看待数据的结果。
对于浮点型数据在内存中的存储,与整型相比又有很大不同,我后续会继续和大家分享,如果本片文章有什么错误之处,欢迎在评论区指出或者私信我^-^,如果觉得本篇文章不错,希望您给个一键三连,我们下期再见!
标签:char,存储,int,补码,C语言,---,整型,类型,原码 From: https://blog.51cto.com/u_16191221/7425709