深度分析数据在内存中的存储

今天和大家分享一下数据在内存中是如何存储的。

一.首先我们先来看一下数据类型:

char 1个字节          字符整形

short       2个字节             短整型

int            4个字节         整形

long          4/8             长整型

longlong     8              更长的整形

float 4 单精度浮点数

double 8 双精度浮点数

size of(long)>=sizeof(int) 在32位平台上 long 是4个节、64位平台上 long是8个字节

整形家族

1.char

signed char        字符在内存中其实存的是字符对应的ASCII码值,所以也看做整形。

unsigned char

2.int

signed int

unsigned int

3.short

signed short [int]

unsigned   short[int]

4. long

signed long[int]

unsigned long[int]

5. long long 

signed long long[int]

unsigned long long[int]

在这里边,除了char,其他的  int、short、long、long long  其实都默认是  有符号类型,而char对应的到底是  signed char还是unsigned char取决于编译器。

浮点型家族

只要是小数,就可以用浮点型家族来表示。

float 的精度低,其存储的数据范围小,double的精度高,其存储的数据范围更大

构造类型           其实是一种自定义类型

(1)数组类型: int arr[3]

(2)结构体类型:      struct

(3)枚举类型:      enum

(4)联合类型:    union

指针类型:

int*p

char*a

float*f

void*c

   空类型:

void  表示空类型(无类型)

通常用于函数的返回类型,函数的参数、指针类型。 

  二.整数在内存中的存储

给大家举一个例子:

int  a=20;

a  的二进制序列的原码是       00000000000000000000000000010100

   在内存中存储的是a的补码,因为a是正数,所以补码和原码相同,

  我们用16进制来表示二进制的这些数字,一个16进制的数字表示4个二进制数字,0000  为0

0000  为0      0000为0    0000为0     0000为0、 0000位0    0001为1     0100为4,    

用十六进制表示为         0X 00 00 00  14      ,我们可以看一下它在内存中的存储情况

我们可以看到它的存储方式是    14 00 00 00,那么为什么要这样存储呢?接下来给大家讲两个概

大小端 字节序概念。          大端字节序:把一个数据的高位字节序的内容存放在低地址处,把低位字节序内容放在高地址处,就是大端字节存储。      

00    00    00    14

           低地址                                                                                                               高地址    

小端字节序:把一个数据的高位字节序的内容存放在高地址处,把低位字节序的内容放在低地址处,就是小端字节存储。

14   00   00   00

                    低地址                                                                                            高地址

    有符号  char   的取值范围。-128-127,      在这里最高位的1表示正负。

00000001                            1
00000002                             2
..............
01111111                            127
10000000                           -128              

1000000  1                         -127

..................

11111111                                  -1

         无符号char的取值范围   0-255,在这里最高位的1表示数值

00000000             0
00000001                 1
..............
10000000                 128           1*2^7          最高位表示数值不表示符号
10000001                 129               
10000010                  130
...............                   
11111111                   255

大家来看一下这个题

                              

 为什么会输出这样一个结果呢?

大家请看

对于char   和  signed  char   在vs编译环境下    ,char就是   signed char

   10000000000000000000000000000001             -1原码

       11111111111111111111111111111110                 -1反码

1111111111111111111111111111               补码

发生截断

11111111

高位补充符号位补1

11111111111111111111111111111111

1000000000000000000000000000000

10000000000000000000000000000001

所以最终值为-1;

而对于unsigned  char

再发生截断后,11111111

因为是无符号整数所以高位补0

00000000000000000000000011111111

又因为我们认为他是个正数(无符号数),所以补码原码相同,最终结果就为255.

      大家再来看一下这几个题:

#include<stdio.h>

#include<windows.h>

int main()

{

       unsigned int i=0;

      for(i=9;i>=0;i--)

{

printf("%d\n",i);

Sleep(1000);    //S是大写

return 0;

}

有同学可能会觉得这个题会循环打印9次 ,但其实是个死循环;

 为什么是个死循环呢?因为  unsigned  int 永远大于0,不会存在小于0的情况。

大家再来看一个题

 我们知道strlen算的是\0之前的元素个数,\0大小为0我们看一下  a[i]是个char 类型的数据那么a[i]的取值范围是-128-127,a[i]依次是   -1,-2...........-128,127,126.........1 0,所以一共有255个数据。

三.浮点数的存储规则

任意一个二进制浮点数v可以表示为      (-1)^S*M*2^E

(-1)^S表示符号位,当S=0时,v为正数;S=1时,v为负数

M表示有效数字,大于等于1,小于2.

2^E表示指数位

给大家举个例子:   十进制的5.0  ,写成二进制是101.0,相当于1.01*2^2,按照上面的格式可以得出   S=0,   M=1.01,E=2,

  V=9.5f      在这里f表示数据属于float的意思,   写成二进制是  1001.1    注意小数点后分别是2^-1, 2^-2.........     ( -1)^0 *1.0011*2^3,

S=0,  M=1.0011   E=3,

我们来看一下它究竟是怎样放的:

对于   M和E,在计算机内部保存M时,默认这个数的第一位总是1,因此可以被舍去,只保存后面的小数部分,如保存1.01时,我们只保存 1.01,对于E情况比较复杂,,存入内存时必须再加上一个中间数,对于8位的E,这个中间数是127,对于11位的E,这个数是1023,比如2^10的E是10,所以保存成32位浮点数时,必须保存成 10+127=137,即10001001

如   v=0.5f=0.1=(-1)^0*1*2^-1     S=0,     M=1.0,E=-1,

float    E+127      126进行存储

double    E+1023      1022进行存储

给大家举个例子,

int main()

{

float f=4.5;

4.5

100.1

1.001*2^2;

s=0;  m=1.001   e=2;

e+127=129; 

129  二进制表示为10000001

存储方式为  01000000100100000000000000000000

用十六进制表示为    0x40 90  00 00

又因为是小端字节序存储,我们猜测   00 00  90  40  这样来存储。

可以看到果真是这样。

然而  指数E从内存中取出还可以再分成三种情况:

E不全为0或不全为1       指数E的指针的计算减去127(或1023) ,得到真实值,再将有效数字M加上第一位的1 ,例如上边的f=4.5,其存储方式为  0 100 00001     00100000000000000000000,  将10000001减去127=2 ,尾数部分的1还原回来,所以就是(-1)*^0*1.00100000000000000000*2^(2)     

E全为0时 ,这时我们可以看到e的值特别小,那么m*2(e)  ,一定是个特别小的数字,这时浮点数的指数E等于1-127(或1-1023),即为真实值,这时有效数字不再加上第一位的1,而是还原为0.xxxxx的小数,这样就成为接近于0的一个很小数字  。

E全为1,此时E=255,那么e=255-127=128   那m*2^(128),的数字会特别大,这时有效数字m全为0,表示无穷大   

给大家再举个例子:

#include<stdio.h>

                                        int main()

{

int n=9;

float*p=(float*)&n;

printf("%d,n);

printf("%f,n);

*p=9.0

printf("%d",n);

printf("%f",*p);

return 0;

}

那么为什么会是这样一个结果呢?     我们看第二个结果,当打印的时候 以%f来打印时, 也就是说 我们会认为 n的二进制存储是一个float类型,    拿出来的时候也要按照 float类型来拿,

0 00000000 00000000000000000001001,我们可以看到E为全0,真实的E值则为1-127=-126那么拿出来的结果就是  0.00000000000000000001001*2^-126,会是一个趋向于0的数字。

我们再来看一下第三个printf,因为这次是按照float的形式进行存储的,9.0   二进制表示为 1001.0,

1.0010*2^3,,m为1.001,E=3,          3 二进制表示101   ,所以存储方式   0 00000101 0010000000000000000000,当以%d的形式打印时,我们会把它看做是一个整数,所以这个数很大,而当以%f形式打印时,因为它本身float类型进行存储,所以打印出来的就是float型

                                                                 

  

  

                                                                                                    ,

                                                                                                                                                            

       

      

  

     

          

  

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值