详解数据在内存中的存储

1.数据类型的详细介绍

char      //字符数据类型
short     //短整型
int       //整型数据类型
long      //长整型
long long //更长的整型
float     //单精度浮点数
double    //双精度浮点数

注意:c语言中没有字符串类型

类型的意义:一、决定开辟空间的大小。二、决定看待这个空间的视角

1.1类型的基本归类

整型家族

char
  unsigned char
  signed   char
short 
  unsigned short(int)
  signed short(int)
int 
  unsigned int
  signed int
long
  unsigned long (int)
  signed (int)

因为char类型里面实际上存的是ASCII码值,而ASCII码值是整数,所以char也算整型的一种

注意:一般来说,类型前面若无unsigned和signed默认为signed,但有些编译器下char与signed char不相同

浮点数家族

float
double

构造类型

>数组类型
>结构体类型 struct
>枚举类型   enum
>联合类型   union

指针类型

int *p
char *p
float *p
double *p
void* p

空类型

void表示空类型,可用于函数的返回类型、函数参数、指针参数

2.整型在内存中的储存

2.1原码 反码 补码

原码、反码、补码是计算机表示整型的三种方式,但是在计算机的内存中存储的是补码

对于正数来说:将数值翻译成二进制形式可以得到原码,正数的原码、反码、补码相同

对于负数来说:原码、反码、补码各不相同,首先将数值翻译成二进制可以得到原码,原码除了符号位其他位按位取反得到反码,反码加1得到反码

#include<stdio.h>
int main()
{
  int a=10;
  //原码、反码、补码相同都为00000000 00000000 00000000 00001010
  int b=-10;
  //原码为10000000 00000000 00000000 00001010
  //反码为11111111 11111111 11111111 11110101
  //补码为11111111 11111111 11111111 11110110
  return 0;
}

让我们看看它们在内存中储存是不是符合我们的计算

我们可以看到a,b的内存中的确存储的是补码,但是存放顺序是倒过来的,这是为什么呢?

2.2大端储存与小端储存

小端储存:数据的低位存储在地址的低位,数据的高位存储在地址的高位

大端储存:数据的低位存储在地址的高位,数据的高位存储在地址的低位

让我们返回上面的例子,拿10举例0a属于数据的低位所以存储在了地址的低位(地址从左到右,从上到下递增)

由此得知我的系统是小端储存模式的,那么问题来了我们如何得知我们的系统是何种储存模式呢?

下面是一道百度2015系统工程师的笔试题

请简述大端字节序和小端字节序的概念,设计一个小程序来判断当前机器的字节序

大端字节序和小端字节序的概念前面已经提过,接下来我们来解决这个小程序

代码如下

#include<stdio.h>
int check_sys(int num)
{
    return *(char*)&num;
}
int main()
{
    int num = 1;
    int ret=check_sys(num);
    if (ret == 1)
    {
        printf("小端\n");
    }
    else
    {
        printf("大端\n");
    }
    return 0;
}

在这里我用1这个数字来检验系统,如果是大端储存那么第一个字节存储的是0,而小端储存第一个字节储存的是1,所以我们通过指针的操作拿到第一个字节的数值就可以得知系统是大端储存还是小端储存

为什么有大小端之分:

当寄存器宽度大于一个字节,那么必然存在着一个如何将多个字节安排的问题。因

此就导致了大端存储模式和小端存储模式

3.浮点数在内存中的储存

常见的浮点数:3.14、1E10

浮点数类型:float、double、long double

浮点数表示的范围:float。h中定义

3.1一个例子

int main()
{
int n = 9;
float *pFloat = (float *)&n;
printf("n的值为:%d\n",n);
printf("*pFloat的值为:%f\n",*pFloat);
*pFloat = 9.0;
printf("num的值为:%d\n",n);
printf("*pFloat的值为:%f\n",*pFloat);
return 0;
}

这部分代码打印什么呢?如下

这说明一个道理,整型和浮点数的储存方式在内存中是不同的

3.2浮点数的储存规则

根据国际标准IEEE754,任意一个二进制浮点数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

再比如十进制的-5.0写成二进制为-101.0,也就是-1.01*2^2

对应到上述规则 S=1;M=1.01,E=2

对于32位浮点数来说,最高1位是字符位S,接下来8位是指数E,剩下的23位存放有效数字M

对于64位浮点数来说,最高1位是字符位S,接下来11位是指数E,剩下的52位存放有效数组M

你可能有疑问,有效数字里不是有小数点吗,怎么储存?

其实IEEE754对有效数字有特别规定

我们发现当有效数字的形式总是1.xxxxxx,因此计算机保存M的时候只保存小数点后面的数字,比如保存1.01的时候先把小数点后面的数字储存,等到读取的时候再把第一位的1加上去,这样可以节省一位有效数字。

而对于指数E也有些特别规定

E的存入

在我们的常识中,E是可以有负数的,但是在编译器中E是无符号整数,这就意味着E储存不了负数,为了解决这个问题,IEEE 754规定存入E的真实值之前必须加上一个中间值,对于32位浮点数这个中间值位127,对于64位浮点数这个中间值位1023,比如在32位浮点数下,E若为20,存入内存中则是147

E的取出

E若不全为0或不全为1,那么将指数E减去127(1023)得到真实值正常进行计算就好

E若全为0,此时E的真实值为1-127(1-1023),并且有效数值不再加上第一位的1,而是还原为0.xxxxx的小数

E若全为1,E的真实值为255-127(2047-1023)

接下来就可以解释刚开始的题目了

整型9在内存中存储的是0000 0000 0000 0000 0000 0000 0000 1001

若用浮点数的视角看待,此时S=0,E=0,M=000 0000 0000 0000 0000 1001

于是浮点数就写成V=(-1)^0 × 0.00000000000000000001001×2^(-126)=1.001×2^(-146)

于是用十进制小数表示就是0.000000

浮点数9.0,V=1.001*2^3,此时S=0,M=1.001,E=3

在内存中储存是0 10000010 001 0000 0000 0000 0000 0000

这个数翻译成10进制正是1091567616

END

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值