您的位置:首页 > 其它

int、unsigned int、float、double和char在内存中存储方式

2017-12-27 18:03 381 查看
2017-12-28  创建人:Ruo_Xiao
实验环境:vs2010、Intel
邮箱:xclsoftware@163.com
2018-01-16  修改人:Ruo_Xiao
添加对移位存储的说明。


零、基础知识

原码、反码和补码是计算机存储数字的编码方式(表示方法)。

拓展:ASCII码、utf-8和utf-16是计算机存储字符的编码方式。

原码:符号位+数值的绝对值。

(1)以8位为例,1的原码为 0000 0001,-1的原码为 1000 0001。

(2)取值范围:11111111 ~ 01111111,即:-127 ~ 127。

反码:正数的反码是原码,负数的反码是在原码的基础上符号位不变,其他位取反的结果。

以8位为例:1的反码为 0000 0001,-1的反码为 1111 1110。

补码:正数的补码是原码,负数的补码是在原码的基础上符号位不变,其他位取反再加一,即:反码+1。

以8位为例:1的补码为 0000 0001,-1的补码为 1111 1111。

补码存在的意义

(1)1 - 1 = 1 + (-1) = (0000 0001)(原) + (1000 0001)(原) = (1000 0010)(原) = -2。错误

(2)3 + 5 = (0000 0011)(原) + (0000 0101)(原) = (0000 1000)(原) = 8。正确

(3)反码相减:3 - 4 = (0000 0011)(原) + (1000 0100)(原) = (0000 0011)(反) + (1111 1011)(反) = (1111 1110)(反) = (1000 0001)(原) = -1。正确

(4)反码相减:5 - 3 = (0000 0101)(原) + (1000 0011)(原) = (0000 0101)(反) + (1111 1100)(反) + 1(循环进位)= (0000 0010)(反) = (0000 0010)(原) = 2。正确

(5)1 - 1 = 1 + (-1) = (0000 0001)(反) + (1111 1110)(反) = (1111 1111)(反) = (1000 0000) = -0。

(6)1 - 1 = (0000 0001)(原) + (1000 0001)(原) = (0000 0001)(补) + (1111 1111)(补)= (0000 0000) (补) = (0000 0000) (原) = 0。

(7)-1-127 = (1000 0001)(原) + (1111 1111)(原) = (1111 1111)(补) + (1000 0001)(补) = (1000 0000)(补) = -128。

A、由(1)和(2)可知,原码相加是正确的,但是相减是错误的。

B、由(3)和(4)可知,反码相加减都是正确的。

C、但是由(5)可知,1-1的反码结果为-0,这个结果在数学上是没有意义的,为了解决这个问题,引入了补码。因为补码是在反码的基础上加1,故补码的加减是没有问题的,关键是1-1了。由(6)可知,补码完美的解决了1-1等于-0的尴尬局面,直接得到0。

D、由(7)可知,计算机底层算法规定了补码1000 0000 = -128。这也就导致了补码的取值范围由-127~127变为-128~127。

总结:

(1)由于原码相减结果不对,故使用了反码。但是反码1-1得到的结果是-0,这个在数学上是无意义的,为了导出1-1=0的正确结果,故使用了补码,同时规定补码1000 0000 = -128,从而可以将-0表示为-128,拓展了一个表示位,故8位二进制取值范围为-128~127。

(2)这里再次强调,在计算机中,数据都是以正数的补码的形式存在的。正数的补码是其本身,负数则是以其本身的正数的补码的形式存在的。

栗子:-123在计算机中的存储的值是1111 1011 -> 1000 0100 -> 1000 0101。

一、int

占用4个字节,即:32b,有符号位:从左数第一位。

取值范围:-2^31 ~ 2^31-1。

原因:0 代表 +0,-0 代表 -2^31,故负数比整数多一个。

数据以补码的形式存放在内存中。

对于+0和-0在内存中的存储方式。

#include "stdafx.h"
#include <iostream>
using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
int i = +0;
int k = -0;
int *pi = &i;
int *pk = &k;

char c = '1';
char *pc = &c;

cout<<"int: "<<sizeof(int)<<" byte"<<endl;
cout<<"unsigned int: "<<sizeof(unsigned int)<<" byte"<<endl;
cout<<"float: "<<sizeof(float)<<" byte"<<endl;
cout<<"double: "<<sizeof(double)<<" byte"<<endl;
cout<<"char: "<<sizeof(char)<<" byte"<<endl;
cin.get();

return 0;
}










二、unsigned int

占用4个字节,即:32b,无符号位。

取值范围:0 ~ 2^32。

数据以补码的形式存放在内存中。

三、float



1. 浮点数在计算机中用科学计数法表示,栗:1.0100011*2^7。

2. 符号位:“+”或者“-”。

3. 指数部分:2的幂指数,栗子中的“7”。

4. 尾数部分:最高位为“1”的底数,栗子中的“10100011”。

5. 栗子:15.987在计算机中存储方式。

(1)15.987的整数部分原码:1111。

(2)15.987的小数部分原码:11111100……此处省略11位。

拓展:小数二进制的计算方法:乘2取整,顺序排列。

栗:0.987的二进制的计算过程如下:0.987*2 = 1.974,则第一位为“1”,0.974*2 = 1.948,第二位为“1”,0.948*2 = 1.896,,第三位为“1”,依次类推,直至结果的小数为0。当然肯定有无穷尽的,这种情况就是计算机存储浮点数的精度的问题了。所以,只有让整数部分和小数部分的位数和为24位(隐藏位技术)即可。此栗中,小数精度为20位。

(3)经过上述计算,15.987的二进制为1111.11111100……,用科学计数法表示为1.11111111100……*2^3。

(4)指数部分采用移位存储的方式,即3+(2^7-1) = 130。其二进制:10000010。

(5)尾数部分省略科学计数法的整数部分!!(因为肯定是1)(隐藏位)

(6)15.987在内存中的存放的内容为:

符号位:0(共1位)。

指数部分:10000010(共8位)。

尾数部分:111111111000……(共23位)。

(7)写成完整的二进制:0100 0001 0111 1111 1100 0……

(8)写成16进制:41 7F C……。

(9)因为Intel的架构的字节序是小端序,则真正的存放内容为……C 7F 41。

四、double



原理同上!

五、char

在内存中以ASCII码的形式存储。

栗子:





代码中字符是“1”,ASCII码为49,转换为16进制为31。

六、拓展

移位存储:

在存储浮点数时,若指数部分若不使用移位存储技术,则会导致0有两种表示方式:1000 000 0和0000 000 0。所以,为了最大化利用价值,同时保留正负性,在原数据的基础上加127,其结果如下:

0000 000 0~0111 111 1代表着-127~0。

1000 000 0~1111 111 1代表着1~127。

这样正负指数均可表示的数量保持一致。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: