一,整数
1,大小端字节序存储
了解大小端字节序存储是了解整数数据存储的前提。大小端字节序存储针对于超过一个字节的数据。
大端字节序(Big-Endian)。在这种字节序中,数据的高位字节(Most Significant Byte, MSB)存储在内存的低地址中,而数据的高位字节(Least Significant Byte, LSB)存储在内存的高地址中。
小端字节序(Little-Endian)。在这种字节序中,数据的高位字节(MSB)存储在内存的高地址中,而数据的高位字节(LSB)存储在内存的低地址中。
例如,我们定义以十六进制的方法定义一个整型n变量
对于十六进制中,数值的高位低位如图所示
如果为大端字节序存储,那么数据的低位字节内容会存储于高位地址,高位字节内容则会被存储于低位地址。如下图所示:
如果为小端字节序储存,那么数据的低位字节内容会存储于低地址,高位字节内容则会被存储于高地址。如下图所示:
当然,字节序的不同储存跟编译器有关,如果不知道自己所使用的编译器属于哪个类型的话,可以使用如下代码进行判断。
int main()
{
int n = 1;//0x00 00 00 01
if (*(char*)&n == 1)
{
printf("小端字节序");
}
else
{
printf("大端字节序");
}
return 0;
}
2,原码,反码,补码
首先我们需要知道,整数在内存中都是通过二进制补码的方式进行存储。原码是整数的二进制形式,最高位代表着符号位(0表示正,1表示负);反码则是在原码的基础上按位取反(0变为1,1变为0,符号位不变!);补码则是在反码的基础上加上1。而我们同时也需要知道正数的原码、反码、补码都是它本身。
例:
3,类型的范围大小限制的原由(以char为例)
char分为两种类型,一种为有符号char(char或者signed char),另一种为无符号char(unsigned char),我们分开来计算两种类型的char的范围大小。
1,有符号char
我们都知道,char类型大小为1个字节(8个bit位),而每一个bit位都存储这一个二进制数字0或者1。所以我们可以很轻松的算出有符号char类型的大小为-128~+127。
依照顺时针方向,我们可以画出有符号char类型的数值循环图。
2,无符号char
对于无符号char,那么它将不会再拥有符号位,即使是在高位也会被编译器视作数值位。所以,无符号char(unsigned char)类型的大小为0~255。
当然,无符号char类型的数值循环图也与有符号char的相同,只不过所表示的数值不同而已
而相关的其他类型例如int,short,long等等都可以用此方法去计算,但是数值较大,难以计算,而我们只需要掌握char类型计算方式就足够了。
二,浮点数
1,二进制的科学计数法
对于浮点数的储存,我们需要首先了解二进制的科学计数法。
例如我们以5.5为例子。5.5的二进制表达式为101.1,但这并不是二进制的科学计数法形式,而二进制形式为1.011*2^2。如果小数点向左移,则对应乘上2的几次方;如果小数点向右移,则对应乘上2的负几次方。
2,IEEE浮点数储存标准
对于浮点数,则有着自己完全不同于整数的储存标准。一个浮点数可以被写为以下形式。
其中s控制着浮点数的正负值,0表示整数,1表示负数。M取值只可以大于等于1,小于2。E则表示2的几次方。所以于内存中,我们只需要储存S、M、E分别所对应的值就可以等效储存一个浮点数了。
对于float(4个字节==32个比特位):
对于double(8个字节==64个比特位):
3,M,E的特别存储方式
对于M,因为M总是被写为1.(....),所以内存在储存的时候会直接省去M中的1,只存放小数点之后的数据。这样做也很好的增大了内存储存数据的容量。
对于E,E被视为无符号整数,那如果E为负数怎么办呢?
在存储E时,我们会对E做出改变。我们会将E的值加上浮点数类型的中间值,然后再转化为二进制数储存于内存中。float类型的中间值为127,double类型的中间值为1023。
举个例子:对于float类型的变量,如果将数据转化为二进制后E等于10,那么计算机会将E加上float的中间数127,为137再进行储存,即10001001。而对于double类型则规则也相同可以进行类推。
对于数据的储存,这就是我目前的见解,希望可以帮助到你们,也欢迎指正!