# 0.11 数据在内存的存储

{% embed url="<https://github.com/labspc/Cnippets/blob/main/.gitbook/assets/0.11%20%E6%95%B0%E6%8D%AE%E5%9C%A8%E5%86%85%E5%AD%98%E7%9A%84%E5%AD%98%E5%82%A8.pdf>" %}
0.11 数据在内存的存储.pdf
{% endembed %}

数据在内存中到底是怎么存的？

## 一、数据类型（内置）介绍 <a href="#tiraz" id="tiraz"></a>

![](https://cdn.nlark.com/yuque/0/2023/png/1171985/1700352712672-d6bdc4a5-4529-497a-a8ec-614b2ec8d092.png)

这里，看看 long 和 int 到底是什么定义的。

![](https://cdn.nlark.com/yuque/0/2023/png/1171985/1700352748872-b6eba49b-f9f2-4320-add5-4165a0a7f7ee.png)

大小决定使用范围！ 这句话，讲的很好。

### 1.1 整型家族 <a href="#inlxj" id="inlxj"></a>

![](https://cdn.nlark.com/yuque/0/2023/png/1171985/1700353430870-eecf267d-2278-43f0-8645-90a998b7a920.png)

unsigned 和 signed 的用处？ signed 最高位是有符号位，没有意义，不是有效数值。 但是，unsigned 就有意义，每一位都可以表示有效数值。 这一部分，我用红笔，隔开了。 没有负数的，就是 unsigned

![](https://cdn.nlark.com/yuque/0/2023/png/1171985/1700353857912-4c777ac3-c9d4-4bac-b458-1e823e1dc8e4.png)

### 1.2 浮点型家族 <a href="#qirmx" id="qirmx"></a>

![](https://cdn.nlark.com/yuque/0/2023/png/1171985/1700354029324-5526524c-097f-484b-80d7-d781457865ac.png)

### 1.3 构造类型 <a href="#kpw7k" id="kpw7k"></a>

![](https://cdn.nlark.com/yuque/0/2023/png/1171985/1700354146897-b8ef2fb1-f17e-4cf0-9817-531a6118f930.png)

先知道有什么，后面再说。

### 1.4 指针类型 <a href="#lzkkp" id="lzkkp"></a>

![](https://cdn.nlark.com/yuque/0/2023/png/1171985/1700354189037-9e8f4459-c796-4fa9-a8ea-39d3fa5cc009.png)

先知道后面再说，

### 1.5 空类型 <a href="#z4ig7" id="z4ig7"></a>

![](https://cdn.nlark.com/yuque/0/2023/png/1171985/1700354278426-c08f6233-0bfb-495e-bd13-a270d9baa71f.png)

## 二、整形在内存中的存储 <a href="#pmd4w" id="pmd4w"></a>

![](https://cdn.nlark.com/yuque/0/2023/png/1171985/1700354521302-af1598bb-40ae-4206-b9ab-d89e943f2522.png)

补码可以把加法和减法统一处理。

![](https://cdn.nlark.com/yuque/0/2023/png/1171985/1700354835410-4362ddca-a83d-4620-87fe-76dd06071f58.png)

计算： 1-1 >> 1+(-1) 可以看到，原码计算会出错， 补码计算，会成32+1 位， 33位，最高位，符号位会丢掉。 但是在计算的时候 实际上是参与运算了， 只是 int 定义为32位， 直接丢掉最高位， 这是c语言设计的哲学， 这样计算就没有问题。 但是在计算的时候，根本没有去思考，到底哪一位是数值位，哪一位是符号位，直接就算了。 这就是“ 将符号位和数值位进行统一”。

![](https://cdn.nlark.com/yuque/0/2023/png/1171985/1700354914284-c5e4f12a-06b4-485a-8c66-acf7efc6125a.png)

想想背后的设计者的 伟大！

原码和补码的相互转换，不需要额外的硬件电路。 >> 计算逻辑是一样的， 就是 取反 +1

## 三、大小端 <a href="#ivgpj" id="ivgpj"></a>

数据在内存中到底是按照什么规则来存储的？ 低到高 或者 高到低 这是两种 存储方式

![](https://cdn.nlark.com/yuque/0/2023/png/1171985/1700360865079-23adeaaf-a9f4-496f-bc85-6c69a11f48cd.png)

这东西，记住就行。

![](https://cdn.nlark.com/yuque/0/2023/png/1171985/1700360957428-1de1d6c0-027b-481f-b905-b0e0da07045d.png)

![](https://cdn.nlark.com/yuque/0/2023/png/1171985/1700361283889-60c16714-80a0-4ff4-b19f-de24c270ca9d.png)

怎么拿 起始地址？ \&a >> int \* 类型 这就找到a \&a取的是起始地址 \*\&a 就是取地址a，访问这个a，int \* 是 四个字节 。

插入：

怎么进行强制类型转换，int转换成char：

```
int a = 42; // 假设a是一个int类型的变量
int *ptr = &a; // 指针ptr指向a

char *char_ptr = (char *)ptr; // 将int类型的指针转换为char类型的指针
```

这里使用了类型转换(char \*)将int类型的指针ptr转换为char类型的指针char\_ptr。

\*\&a 就是取地址a，访问这个a，int \* 是 四个字节 。 `*(char*)&a` 强制类型转换为char \* `*` >> `(char *)&a` 就是拿第一个字节 因为 char \* 是1字节。

\&a ： 整型指针解引用，访问的是4个字节， char\* 强制类型转换， 就是1字节 `*(char*)&a` 这里还有一个强制类型转换，确实很6.

这里比较难理解其实，花了一下午时间去搞，中途还复习了二级指针。你最后看这个代码的呈现，确实很巧妙，用一个条件来表示想法，用if进行判断，太棒了这个程序，但是它背后却是一系列很复杂的思考。

![](https://cdn.nlark.com/yuque/0/2023/png/1171985/1700387654219-ffb46f06-ed95-4598-a184-57e3e3e26a86.png)

```
#include <stdio.h>
int main()
{

    int a = 1; // 假设a是一个int类型的变量

    if (*(char *)&a == 1 /* condition */)
    {
        /* code */
        printf("XD\n");
    }
    else
    {
        printf("DD\n");
    }
    printf("%p\n", &a);
    printf("%d\n", a);

    return 0;
}
```

第二种比较啰嗦的写法：

```
int main()
{
    int a = 1;
    int *b = &a;  // 取a的地址，用指针b来存
    int **c = &b; // 二级指针

    int d = *&a; // 访问a >> int*  4个字节

    char *e = (char *)b; // 将int指针类型转换为char指针类型

    printf("&a Address of a is %p\n", &a);
    printf("*b Address of a is %d\n", *b);
    printf("**c Address of a is %d\n", **c);

    printf("d Address of a is %d\n", d); // d >> a=1

    printf("e Address of a is %p\n", (void *)e); // 打印char指针的地址，转换为void *类型

    if (*e == 1 /* condition */)
    {
        /* code */
        printf("XD\n");
    }
    else
    {
        printf("DD\n");
    }
    return 0;
}
```

![](https://cdn.nlark.com/yuque/0/2023/png/1171985/1700388760715-1f7bbb97-0646-43be-be94-d25d9d532a98.png)

## 三、浮点型在内存中的存储 <a href="#j8asi" id="j8asi"></a>

2023-11-20 更

小数和浮点数在内存中有可能无法完全保存，会有精度丢失的问题。以下仅为举例说明，具体看ipad有演算。

![](https://cdn.nlark.com/yuque/0/2023/png/1171985/1700469454058-2fad09be-a9fc-40ed-825a-d7e1ef59cbe6.png)

浮点数在内存中具体存储，SME， 规则如下：

32位 。 1 8 23

![](https://cdn.nlark.com/yuque/0/2023/png/1171985/1700469582186-90f31b5b-ed14-49fd-bdf4-b4ee8d0b2290.png)

64位 。 1 。 11 。 52

![](https://cdn.nlark.com/yuque/0/2023/png/1171985/1700469637846-393e9372-741c-4e72-8254-52c2df6e82e0.png)

这个规则也是记住就行，

![](https://cdn.nlark.com/yuque/0/2023/png/1171985/1700469766444-095ed008-7850-4701-960e-ec110fb746a7.png)

### 3.1 关于E的存储。 的举例说明 <a href="#haizg" id="haizg"></a>

![](https://cdn.nlark.com/yuque/0/2023/png/1171985/1700470095890-688fb063-2231-45e4-ac24-957ee9f4e716.png)

![](https://cdn.nlark.com/yuque/0/2023/png/1171985/1700470159977-e04b66b9-8838-49ae-a7bb-61380d6d852c.png)

代码举例： S >> E >> M 存储 最后写成16进制 注：还可以看到，不够的话，可以在有效值M 后 补0占位

![](https://cdn.nlark.com/yuque/0/2023/png/1171985/1700470368400-82d15ecc-b3e0-465e-926a-1c673741d442.png)

![](https://cdn.nlark.com/yuque/0/2023/png/1171985/1700470395002-7e02e460-b543-4694-9655-49e5a798d396.png) 这是小端存储
