您的位置:首页 > 编程语言 > C语言/C++

基础数据在内存中的存储-C语言

2014-06-17 17:02 288 查看

在计算机中所有的数据存储都是二进制

1 十进制与二进制的转换

1.1 二进制转十进制

假如数据10.101,对应各个位数 为 ab.cde ,则转换为十进制的数据
a*2的1次方+ b*2的0次方+c*2的-1次方+d*2的-2次方 +e*2的-3次方
1*2(1)+0*2(0) + 1*2(-1)+0*2(-2)+1*2(-3)

1.2 十进制转二进制

整数:除2取余,逆序排列,用2整除十进制数,得到 商 和余数,然后在用2整除商,再得到商和余数,循环进行,直到商为0 ,最后把余数逆序排列。
以下以10为例
10(十进制)
商 余数

10/2 5 0
5/2 2 1
2/2 1 0
1/2 0 1
1010(二进制)
小数 :乘2取整,顺序排列,用2乘十进制小数,得到积,把整数部分取出,再用2乘余下的小数部分,又得到一个积,再把积的整数部分取出,循环进行,直到积中的小数部分为零,或者达到要求的精度,最后把整数部分顺序排列
例1
0.125(十进制)
--------------------------------
积 整数部分
0.125*2 0.25 0
0.25*2 0.5 0
0.5*2 1.0 1
0.001(二进制)

例2

0.11(十进制)
--------------------------------
0.11 *2 0.22 0
0.22*2 0.44 0
0.44*2 0.88 0
0.88*2 1.76 1
0.76*2 1.52 1
0.52*2 1.04 1
0.04*2 0.08 0
。。。。。。。
无穷尽,如果要用32个二进制位存储这个数据,只能舍弃低位,保留高位。
得到二进制数0.0001110...

2、char int short long 存储

对于这几种类型的变量,都是用来存储
整数数据,只不过因为所占内存大小不同而表示的数据的范围不同。
看代码的时候要分两个层面:
(1)代码层面,代码根据语法是如何写的。
(2)计算机层面,编译器是如何翻译的。
比如 char 类型,有的人说它是字符类型,存储的是字符,这个理解是不全面的。
char a = 1; char 占1个字节可以表示数据 0-255,当然可以存储整数数据1.
char a = '1'; 单引号括起来的是字符数据,这是我们人类理解的概念,人在写代码的时候是能看明白的,但是计算机不明白,这就要用编译器来给它翻译过来,最终计算机存储的是 字符'1' 的ascii码,其实这个ascii码也是个整数数据。

最终 整数数据 都转化成二进制存储到了计算机中,并且用的是补码。

2.1 为什么要补码

如果只有 大于0的数和加法,那么就不需要补码这个东西。

(1)计算机硬件支持加法 ,如果要支持减法要额外硬件电路,但是减法可以用加法加上一个负数来代替,所以按照这个思路就省了这部分硬件。
(2)模的概念
a 如果一个数据的范围是 0-9,那么就是有10个有效状态,10就是这个数据的模
b 在模的概念下 假定模 是M , X+Y = M ,我们说X与Y 互补。
c 两个互补的数在模的概念下 可以互为 负数 :比如
时钟 一圈的数字 是 0-11,它的模是12, 那么如果我现在在0初去转表针,想转到3的位置,则
我可以是正转 3下,也可以反转9下,所以在模为12的这个系统下,可以用3代表-9。
(3)对于一个字节的char 变量来说 ,占8bit ,可以表示256个状态,表示非负数 0-255,模为256.
当数据为 1111 1111 时,再+1 则得到的数据 为 1 0000 0000,最终会舍弃最高位的1,保留0000 0000,这样一圈又回归到0了。
如果要表示负数,则一分未二,128个负数,128个非负数,最高位为符号位,当为1时,表示负数,0时表示非负数。

2.2 如何求补码

(1)非负数补码 = 原码
(2)负数补码 = 反码+1,计算规则是,符号位不变,其他位按位取反,最后这个数据+1
比如 -1 如下算法
0000 0001 正1
1000 0001 如果是负数,则符号位为1
1111 1110 符号位不变,其他位按位取反
1111 1111 再+1 得到-1的补码。
如下计算:
1-1 --》 1+(-1) --》0000 0001 + 1111 1111 = 1 0000 0000 溢出,舍弃最高位,是不是又回归0了?
(3)1000 0000 表示的数字是多少?
1000 0000 表示的数字 是 -128,而不是 -0;
-----------------------------------------------
假定有 -0这个数,则在内存中
1000 0000
1111 1111 符号位不变,其他取反
10000 0000 再加1溢出,舍弃最高位,内存中依然是 0000 0000;
-----------------------------------------------
-128的补码是按照以下方法算的,因为一个字节最高位是符号位,没法表示128,所以算的的时候又借了一个字节
1000 0000 1000 0000 在16位中-128原码
1111 1111 0111 1111 取反
1111 1111 1000 0000 +1得出16位中-128的补码,存到1字节中,舍弃高位,为 1000 0000

3 float double数据的存储

float 和 double 数据在内存中的存储方式相同,只不过由于所占字节大小不同而导致数值范围和精度不同。
以下以float数据为例,4个字节按照如下分配:





(1)科学计数法
对于 十进制数 223.456,换算成科学计数法 2.23456 * 10的2次方
对于二进制小数 1101.111 换算成科学计数法 为 1.10111 * 2的3次方

(2)在计算机内部,float数的存储,先换算成二进制的 科学计数法形式,然后分别把 尾数和指数部分存储到内存中。
比如 1.10111*2的3次方,则在 8位指数位中要存储 3 ,23位尾数位要存储 110111。
对于二进制数来说,最高位永远是1 所以最高位1就省略了,23位二进制位其实表示了24位尾数,所以存的是10111,
由于指数部分有正负 ,范围是-127--128,在这里按照移位存储,3+127 ,所以存储的是127+3
对于1101.111在内存中存储的是如下:



(3)对于以下代码
float a = 0.125;
float b = 0.123;
根据十进制转化为二进制的算法,a是有穷的,并且在23位尾数中可以完全存储,所有内存中存的就是0.125;
对于b来说,转化的二进制数是无穷的,当把尾数放到23位二进制位存储的时候必然要舍弃低位数据,所以这里的存储肯定是不准确的。
-------------------------------------------------------------------------------------
所以对于一个 int a_int 来说,可以写出 if(a_int == 2)这样的表达式。
对于 float a_float 来说,不能写这样的if(a_float == 1.2)这样的表达式。
同样swtich语句可以switch(a_int),而不能switch(a_float)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: