数据在内存中的存储(剖析)

简介: 数据在内存中的存储(剖析)

数据的基本类型

       c语言中,有着许多基本类型,而这些基本类型大部分都是内置类型,故名思意,就是在这个语言中最基本的类型;同时内置类型也是各个语言在设计初期所定义的类型

常见的类型

char         -        1Byte         -         8bit        -        字符类型

short        -        2Byte         -       16bit        -        短整型

int            -        4Byte         -       32bit        -        整形

long         -        4Byte / 8Byte         -        32bit / 64bit        -        长整型

long long        -        8Byte        -        64bit        -        更长整形

float        -        4Byte          -        32bit        -        单精度浮点型

dauble     -        8Byte      -        64bit        -        双精度浮点型

数据的基本类型归类

       在c语言中,不同的类型有着不同的意义;不同的类型决定在内存中开辟空间的大小以及在内存中存储的方式,而在c语言中,我们也可以为这些类型进行归类。

整形类型

char

       char    

 ( C标准中对char是 Impementation Defined,就是未明确定义)

       unsigned char

      signed char


short

       (signed) short

       unsigned short


int

       (signed) int

       unsigned int


long

      (signed) long

       unsigned long


long long

       (signed) long long

       unsigned long long

浮点数类型

float

dauble

构造类型

数组类型


结构体类型 - struct


枚举类型 - enum


联合类型 - union

指针类型

int* pa;           -        整形指针        -        指向整形的指针

char* pb;        -        字符指针        -        指向字符的指针

float* pc;        -        浮点型指针        -        指向浮点数的指针

void* pd;        -        空指针        -        不指向任何类型的指针

空类型

void        -        空类型(无类型)        -        通常用于函数的返回类型,指针类型


数据在内存中的存储形式

       在c语言中,任何数据都是存储在内存中的,但是不同类型数据存储的方式以及读取方式都大不相同。

整形的存储形式

       在c语言中,数据的存储方式一般都是由二进制进行存储,而在一个整形数据的二进制中,有三种表达方式:

原码                反码                补码


原码

       原码就是将一个整数转换为二进制的形式,就是其原码,当一个数据为一个有符号的数据时其最高位为符号位

例:

int a =  13;   //    -    0000 0000 0000 0000 0000 0000 0000 1101
int b = -15;   //    -    1000 0000 0000 0000 0000 0000 0000 1111

13 与 -15 的二进制位即为它们的原码


反码

      负数的反码即为将原码符号位(首位)以外所有的二进制位 ( 数值位 ) 按位取反,也就是1变为0,0变为1。

以-15为例:

int b = -15;
//1000 0000 0000 0000 0000 0000 0000 1111    -    原码
//1111 1111 1111 1111 1111 1111 1111 0000    -    反码

但是对于正数来说,它的原码反码补码都相同;


补码

      负数的补码就是其反码再加上1,而在计算机内存中,存储整形类型数据时一般都为补码。

int b = -15;
//1000 0000 0000 0000 0000 0000 0000 1111    -    原码
//1111 1111 1111 1111 1111 1111 1111 0000    -    反码
//1111 1111 1111 1111 1111 1111 1111 0001    -    补码

对于正数来说,它的原码反码补码都相同;


二进制位转为十六进制位时,每四位二进制位则表示一位十六进制位

则 -15 转换为十六进制位时则为"FF FF FF F1"

(从右往左读)


大小端

       从上面的图可知,数据在内存中的存储不仅与原反补码有关,而且与某些因素也有关,在内存中存进去的十六进制位为"FF FF FF F1",但是在内存中显示的又是"F1 FF FF FF" 。该处就涉及到一个计算机的大小端问题。

       大小端是一种表现形式,这种表现形式只出现在数据存储在内存中,而不是在寄存器中参与运算时的表现。

       计算机在内存中存放数据的顺序都是从低地址到高地址,所不同的是首先取低字节的数据存放在低地址还是取高字节数据存放在低地址,这就是大小端的问题

大端       -        把一个数据的低位字节,存放在高地址处高位字节,存放在低地址处

小端       -        把一个数据的低位字节,存放在低地址处高位字节,存放在高地址处

在c语言中,也可设计程序来判断机器的大小端。

#include<stdio.h>
int check()
{
  int n = 1;//创建变量n初始化为1
  char* p = &n;//创建一个字符指针指向地址的前一个字节并返回
  return *p;
}
int main()
{
  if (check()) {//1在存储中若是小端则会存储在高地址处则为小端
    printf("小端\n");
  }
  else {
    printf("大端\n");//若是大端则会存储在低地址处
  }
  return 0;
}

浮点型在内存中的存储

       浮点数是表示小数的一种方式,浮点数就是小数点的位置不固定,于此相反的由定点数,即小数点的位置固定。在内存中,整形数据是根据二进制的原码反码补码进行存储,而浮点数的存储方式又与整形数据的存储方式截然不同。

       为了规定浮点数在内存中存储的方式,出现了一个国际标准        -       IEEE(电气和电子工程协会) 754,在该标准中规定,任意一个二进制浮点数V都可被表示为下面的形式:

(-1)^S * M * 2^E

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

M代表有效数字,且 2>M>=1。

2^E表示指数位。

以浮点数10.0与-10.0作为例子:

10.0        -        1010.0        -        (-1)^0 * 1.01 * 2^3

                                                          S     M       E

-10.0       -        -1010.0       -        (-1)^1 * 1.01 * 2^3


IEEE 754中规定

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


对于64位的浮点数在内存中的存储形式为,最高1位为符号位S,接着的11位为指数E,剩下的52位为有效数字M


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

在规定中

S被正常保存,非0即1;(0代表V为正数,1代表V为负数)


M在内存中的保存形式为只保存有效数字小数点后面  . xxxxxx  部分,因为在一个小数中,利用科学计数法可以将任何非0的小数写为 1.xxxx * 2^E 的形式:

( -0.5      -       -0.1      -     1.0 * 2^-2)

在浮点数的保存形式中

例:

1        1        1        1        .        1        1        1        1

权重                       2^3     2^2    2^1    2^0           2^-1   2^-2    2^-3   2^-4

(故 -0.5        -        -0.1)

又因能确保浮点数在内存中存储时能做到更高的精度,故M只保留有效数字  . xxxxxx  部分。

但也不是所有浮点数都能被完全没有误差的保存;

例如存入一个浮点数为4.4

小数点前的数可以利用0100来表示,但是小数点后的 .4 却不能没有误差的进行保存,根据权重算出,小数点后第一位为0.5,第二位为0.25,第三位为0.125......


E在内存中的保存形式,因为E为一个unsigned int类型的数值 - 即无符号整形

若是32位的浮点数,该范围为0 ~ 255

若是64位的浮点数,该范围为0 ~ 2047

       而在浮点数用科学技术法的表现形式下,E难免出现负数,为了不在内存中出现存储错误,IEEE 754标准规定 E 在保存中应先加上一个中间值,即127或1023,在32位浮点数的情况下,加上127;64位浮点数的情况下,加上1023。

根据上述规定我们可知,如果存在2个变量

float ph = 10.5 ,pn = -0.5;

即10.5在内存的存储形式为

10.5        -        1010.1        -        1.0101 * 2^3        -        V = (-1)^0 * 1.0101 * 2^3

S = 0(V为正数)

E = 3+127 = 130        -        1000 0010

M = 0101

0 10000010 01010000000000000000000

2进制每4位为一个16进制数

换为16进制即为 01000001001010000000000000000000        -       41 28 00 00


同样 -0.5在内存中的存储形式为

-0.5        -        -0.1        -        1.0 * 2^-1        -        V = (-1)^1 * 1.0 * 2^-1

S = 1(V为负数)

E = (-1)+127 = 126        -        0111 1110

M = 0

1 01111110 00000000000000000000000

换为16进制即为10111111000000000000000000000000       -        BF 00 00 00 00

 


浮点数从内存中的取出

       在内存中,数据不仅需要存储,在使用时还需要取出,浮点数也是如此,在存储中,采用了IEEE 754的标准。

       同样在取出数据的过程中IEEE 754也规定了相当的标准。

       共分为3种情况

E不全0也不全1

       规定当E不全0也不全1时,即指数 E 的十进制位减去127或1023得到真实值,有效数值M加上原有的1进行还原。


E全为0

       当E全为0时,浮点数的指数E为1-127或者为1-1023即为真实值,此时M不再加上原有的1,而是还原为0.xxxxxx的形式。通常表示一个极为接近0的数值(其正负取决于符号位S)。


E全为1

       这时的E若为全1的话,表示该数值在浮点数的范围种是一个±无限大的数值(其正负取决于符号位S)。

相关文章
|
7天前
|
存储 编译器 数据处理
C 语言结构体与位域:高效数据组织与内存优化
C语言中的结构体与位域是实现高效数据组织和内存优化的重要工具。结构体允许将不同类型的数据组合成一个整体,而位域则进一步允许对结构体成员的位进行精细控制,以节省内存空间。两者结合使用,可在嵌入式系统等资源受限环境中发挥巨大作用。
28 11
|
30天前
|
监控 算法 应用服务中间件
“四两拨千斤” —— 1.2MB 数据如何吃掉 10GB 内存
一个特殊请求引发服务器内存用量暴涨进而导致进程 OOM 的惨案。
|
29天前
|
存储 C语言
数据在内存中的存储方式
本文介绍了计算机中整数和浮点数的存储方式,包括整数的原码、反码、补码,以及浮点数的IEEE754标准存储格式。同时,探讨了大小端字节序的概念及其判断方法,通过实例代码展示了这些概念的实际应用。
60 1
|
1月前
|
存储
共用体在内存中如何存储数据
共用体(Union)在内存中为所有成员分配同一段内存空间,大小等于最大成员所需的空间。这意味着所有成员共享同一块内存,但同一时间只能存储其中一个成员的数据,无法同时保存多个成员的值。
|
1月前
|
监控 Java easyexcel
面试官:POI大量数据读取内存溢出?如何解决?
【10月更文挑战第14天】 在处理大量数据时,使用Apache POI库读取Excel文件可能会导致内存溢出的问题。这是因为POI在读取Excel文件时,会将整个文档加载到内存中,如果文件过大,就会消耗大量内存。以下是一些解决这一问题的策略:
102 1
|
1月前
|
存储 弹性计算 算法
前端大模型应用笔记(四):如何在资源受限例如1核和1G内存的端侧或ECS上运行一个合适的向量存储库及如何优化
本文探讨了在资源受限的嵌入式设备(如1核处理器和1GB内存)上实现高效向量存储和检索的方法,旨在支持端侧大模型应用。文章分析了Annoy、HNSWLib、NMSLib、FLANN、VP-Trees和Lshbox等向量存储库的特点与适用场景,推荐Annoy作为多数情况下的首选方案,并提出了数据预处理、索引优化、查询优化等策略以提升性能。通过这些方法,即使在资源受限的环境中也能实现高效的向量检索。
|
1月前
|
缓存 安全 Java
使用 Java 内存模型解决多线程中的数据竞争问题
【10月更文挑战第11天】在 Java 多线程编程中,数据竞争是一个常见问题。通过使用 `synchronized` 关键字、`volatile` 关键字、原子类、显式锁、避免共享可变数据、合理设计数据结构、遵循线程安全原则和使用线程池等方法,可以有效解决数据竞争问题,确保程序的正确性和稳定性。
41 2
|
3月前
|
存储 编译器 C语言
【C语言篇】数据在内存中的存储(超详细)
浮点数就采⽤下⾯的规则表⽰,即指数E的真实值加上127(或1023),再将有效数字M去掉整数部分的1。
385 0
|
1月前
|
存储 编译器
数据在内存中的存储
数据在内存中的存储
42 4
|
1月前
|
存储 Java
JVM知识体系学习四:排序规范(happens-before原则)、对象创建过程、对象的内存中存储布局、对象的大小、对象头内容、对象如何定位、对象如何分配
这篇文章详细地介绍了Java对象的创建过程、内存布局、对象头的MarkWord、对象的定位方式以及对象的分配策略,并深入探讨了happens-before原则以确保多线程环境下的正确同步。
56 0
JVM知识体系学习四:排序规范(happens-before原则)、对象创建过程、对象的内存中存储布局、对象的大小、对象头内容、对象如何定位、对象如何分配