1.整数在内存中的存储
(1).原码,反码,补码
我们都知道,一个整数类型的数据,不管是正数还是负数,都是可以转换成二进制类型的数据。而一个整数类型是4个字节,一个字节等于8个比特位,因此,一个整形数据就等于32个比特位。这就意味着在转换成二进制的时候需要小心,避免把0/1写错。
而整数在内存中的存储,则是以二进制的形式来存储的。二进制位的最高位是符号位。对于正整数来说,十进制转换成二进制形式的原码,反码和补码都是一样的,在内存中,存储的是补码;对于负整数来说,十进制转换成二进制形式的原码,反码和补码却都是不一样的。他们之间可以相互转换。反码:在原码的基础上,除了最高位不变,其他的位按位取反。补码:在反码的基础上,最低为+1。而对于补码转换成原码,也是进行相同的操作。
(2).大端存储和小端存储
大端存储和小端存储是两种不同的数据存储方式,对于不同的机器,其存储的方式也有所不同。那么什么是大端存储呢?
大端存储模式:将数据的低位字节存储到高位地址中,高位字节存储到低位地址中
小端存储模式:将数据的低位字节存储到低位地址中,高位字节存储到高位地址中
(3).下面来看几个代码
第一个
#include <stdio.h>
int main()
{
char a = -1;
signed char b = -1;
unsigned char c = -1;
printf("%d %d %d", a, b, c);
return 0;
}
这个代码打印的结果是-1,-1,255。这就让我一开始感觉到非常奇怪,这是为什么呢?
首先来分析一下下代码
我们可以发现,这三个变量的原码反码补码都是一样的,那为什么输出的结果是不一样的?我们继续往下看看~
首先看char a,一个char类型的数据只能存放一个字节大小的数据,但在这里放进去了四个字节的数据,而整形数据在内存中又是按补码存放的。因此,将会发生整型截断,按低位取值,只取低位的那个字节 ---->11111111
而signed char,unsigned char也是一样的。
在使用%d输出时,%d的作用以十进制的形式打印有符号的整形。因此在打印的时候由于他们只有一个字节,因此要进行整型提升。而在VS编译器中,char类型被默认成与signed char类型相同,都是有符号类型的数据,因此对于有符号类型的数据发生整型提升时,看符号位,符号位是几,就往前面补几,补到32位为止。
而对于无符号类型数据,他的每一个位都是有效位,是没有符号位的,因此,在无符号类型发生整型提升时,由于他没有符号位,因此在提升的时候需要往前面补0。
因此就会输出-1,-1,255
第二个
输出的结果是一个非常大的数,与第一个类似,我就不多说了。
2.浮点数在内存中的存储
对于浮点数在内存中的存储,我们首先来看一个东西。
也就是说,如果想存储一个浮点数类型的数据,首先要将其化成二进制的形式,然后再将二进制的形式写成如上图的那种形式。
而在浮点数的存储当中,是以S E M的顺序来存储的。
对于一个32位(float)的浮点数类型,最高一位存储符号位S,接着8位存储指数E,最后剩下的23位存储有效数字M
而对于一个64位(double)的浮点数类型,最高一位存储符号位S,接着11位存储指数E,最后剩下52位存储有效数字M
存储的大概方式我们知道了,那存储规则呢?
以32位的浮点数为例,首先把S存放到第一个比特位,如果是正数就存0,负数就存1;接着把E+127所得到的数字转换成二进制位存入11个比特位中;最后把M存进去,但一般来说,M都是写成1.xxxxxxx的形式的,因此在存储这个数据的时候,我们可以把1给省略掉,只存放小数点后面的数字,如果存完了小数点后的数字还剩余比特位没存的话,就存0上去就可以了