数据在内存中的存储

一、整数在内存中的存储

c语言的数据类型可分为整数和浮点数两大类,我们先来讨论一下整数在内存中的存储方式,首先,对于整数,其二进制形式可以分为,原码,反码,补码三种形式,其中原码的符号位不变,其它位按位取反可以得到反码,再将反码加一,可以得到补码。

1.大小端字节序以及大小端字节序的判断

我们已经知道整数在内存中以补码的形势储存,那么它是怎样以补码的形式储存的呢?我们可以将一个整数的地址打印出来看看

我们可以看到我们放进去的数据是44332211,但是实际在内存中存储的是11223344,是不是意味着我们存入的数据在内存中都是倒序存放的呢?其实并不是,其实主要的原因是数据在这个机器中采用的是小端存储,那么有小段存储也就说明还有大端存储,那么什么是大小端存储呢?其实就是存储时的字节序不一样而已,下面我们引入大,小端存储的概念

(1)小端存储

指数据的低位字节内容保存在内存的低地址处,而数据的高字节内容保存在内存的高地址处

(2) 大端存储

指数据的低位字节内容存储在内存的高地址处,而数据的高位节内容保存在内存的低地址处

现在我们便可以很好的解释为什么我们输入的数据在内存中是倒字节序存储的了

2.判断机器的字节序

现在我们已近了解了机器的存储方式,那么我们如何通过一段代码来判断自己机器的字节序呢?

我们会想,能不能直接打印出来呢?岂不是很直接吗?可是我们知道存储方式是没有打印的方法的,我们知道,一个整形数据的存储有两种字节序,如44332211和11223344,此时我们发现,只需要比较一个字节的内容,就可以判断两个字节序是否相等,我们知道,以上数据是存放在4个字节中的,如今我们只需要比较一个字节的内容就可以判断,那么一个数据占用4个字节,却只需要使用一个字节,是不是和前面我们学习的指针关联起来了呢?下面请看一段代码来看看是如何实现的

我们看到,a是整形,如果用char*类型的指针存放a的地址的话,那么在间接访问的时候便只能访问一个字节了,这正是我们想要的结果。当然如果我们在平常的时候经常这样使用的话,那么大概率是你使用错了,当我们在没有其它特殊用途的时候,要记得什么类型的数据就要使用什么类型的指针哦!其实,一个地址可以存放在任意类型的指针变量中,但能存放不意味着能正常使用,不同类型指针存放同一地址的区别在于1.在间接访问过程中访问的字节数不同 2.在进行指针的加减运算的时候跳过的字节数不同。在上面的代码中,有一个不好的地方,那就是判断字节序的过程是一个·具体的方法,我们把他封装成函数会更好,在这里是为了容易理解。

3.关于整数存储的练习

1.判断a,b,c的值

让我们来分析一下,对于a,其原码为10000000 00000000 00000000 00000001,反码为11111111 11111111 11111111 11111110,补码为11111111111111111111111111111111,然后将其存放在a里,由于a为char类型,只能存放

前八个比特位,即11111111,由于b,c同样以补码形式存放,所以a,b,c中存放的都是11111111

接下来分析它们如何打印,对于a,它是char类型但是打印的是整形,因此我们需要对它进行整型提升,提升的方法为1.对于无符号数,在前面补0即可,补足32位 2.对于有符号数,如果符号位为1,则补1,为0,则补0。因此,我们对a进行整型提升后,可以看到结果还是-1,因此b也为-1,对于c,对其进行整型提升后为00000000 00000000 00000000 11111111,但由于c为无符号数字,因此其原码,反码,补码相等,因此最后打印出来的结果为255。下面请看执行结果

2.判断u的值1

首先,a的原码为10000000 00000000 00000000 10000000,反码11111111 11111111 11111111 01111111,补码11111111 11111111 11111111 10000000,然后将后8个比特位即10000000存入,

然后需要进行整形提升,a是char类型符号位位1,因此提升后为11111111 11111111 11111111 100000000,有因为打印的是无符号整数,因此把这个二进制序列看成无符号数打印,其结果为

4294967168,运行结果如下

3.判断u的值2

从题目中看到,我们想要把128存入字符变量a中,这显然是不行的,因为我们知道char类型占一个字节,只有8个比特位,最高位表示符号位,因此它可以储存的最大正数为01111111,即127,最小负数为10000000,即-128(10000000是-128为人为规定),也就是127+1=-128,也就是说,这题的结果与上一题相同,为4294967168,代码如下

4.判断字符串长度

 我们知道,strlen在计算字符串长度时,只有遇到\0才会停止读取,也就是说此处a[i]=0时,停止读取,字符串长度为0之前的字符串长度,因为此处的a为字符型变量,其可存储的最小数为-128,-128-1=127,然后逐渐减到0,-1到-128有128个数,127到1有127个数,即最后字符串长度为128+127=255。运行结果如下

5.预测以下代码运行结果
<1>

我们知道,unsigned char能够存储的数字范围为0-255,因此i<=255恒成立,即无限循环,运行结果如下

<2>

i为无符号整形变量,因此i的值永远大于0,即无限循环,运行结果如下

二、浮点数在内存中的存储

1.浮点数的表示形式

我们知道,整数的存储要用到原码,反码,补码,但浮点数可不一样,它有它自己的存储方式,可以通过以下代码看出,

运行结果为

根据国际标准IEEE754,任意一个二进制浮点数V可以表示成下面的形式:

V=(-1)^s*M*2^E

其中,(-1)^s表示符号位,S=0时,V为正数,S=1时,V为负数

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

2^E表示指数位

比如:十进制:5.0     二进制:101.0  

可以表示为 1.01*2^2,(其实相当于二进制的科学计数法),其中,101.0为正数,故S=0;

又因为每一个二进制数都可以表示成1.XXX……的形式,所以可以把1省略,即M=0.01,需要使用时系统会自动把1加回去,对于E,不要以为它在内存中是将2储存进去的,其实是将2+127存储进去的,那么为什么要这样做呢?我们来讨论一下

1.对于32位浮点数,最高的1位储存符号位S,接着的8位存储指数E,剩下的23位存储有效数字M

2.对于64位浮点数,最高的1位存储符号位S,接着的11位存储指数E,剩下的52位存储有效数字M

看了这些,我们了解到,符号位已经被S占有了,这意味着存储指数的8个或11个比特位是没有符号位的,即E是无符号数字,既然如此,那我们如何把二进制数0.1存放进去?我们知道0.1=1*2^(-1),可是E是无符号数,存放不了负数-1啊,对此我们可以将指数加127再放进E里面,这样就解决了这个问题,即E=-1+127=126

2.浮点数存储指数时的特殊情况

1.E为全0

这时,浮点数的指数E等于1-127(或者1-1023)即为真实值,有效数字M不再加上第一位的1,而是还原为0.xxxx的小数。这样是为了表示+-0,以及接近于0的很小的数字。

2.E全为1

这时,如果有效数字M全为0,表示+-无穷大(正负取决于符号位S)

  • 24
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值