谈谈数据在内存当中的存储

74 阅读7分钟

谈谈数据在内存当中的存储


1. C语言的数据类型分类

整数型: char(1字节),short(2字节),int(4字节),long(4字节--32位/8字节--64字节)

浮点型: float(4字节),double(8字节)

构造类型: 结构体struct,枚举类型enum,联合类型union(自定义类型)

空类型: void


2. 整型在内存当中的存储

原码 反码 补码

二进制表示形式有 原码 反码 补码

int a = 10;

4个字节 32个比特位

00000000 00000000 00000000 00001010 原

00000000 00000000 00000000 00001010 反

00000000 00000000 00000000 00001010 补
int b = -10;

对于负数来说 反码为原码按位取反 补码为反码+1

原码求补码 补码求原码 都可以通过取反+1进行转换

10000000 00000000 00000000 00001010 原

11111111 11111111 11111111 11110101 反

11111111 11111111 11111111 11110110 补

内存当中0xff ff ff f6 小端法存储(低位存在低地址 高位存在高地址)

截屏2024-07-29 15.27.04.png

截屏2024-07-29 15.36.46.png 使用补码可以将符号位和数值位统一进行处理 最高位是负值相加即得到最后的实际数据:

对于补码的值 最高位看为负权重 其他位正权重 这样即可统一计算正数与负数(csapp第二章)

原码计算是错误的 补码计算才是正确的 如果按照原码进行计算与求值 则最后的结果应该是-2 显然与现实不符

1+(-1)

00000000 00000000 000000000 00000001//1

11111111 11111111 11111111 11111111//-1

00000000 00000000 00000000 00000000//0

大端 小端法存储数据

0x 11 22 33 44 大端字节序存储

0x 44 33 22 11 小端字节序存储
  1. 字节序 - 是以字节为单位讨论存储顺序

  2. 小端字节序存储 把一个数据的低位字节的内容存放在低地址处(常见x86小型机用的都是小端法存储数据)

  3. 大端字节序存储 把一个数据的低位字节的内容存放在高地址处(ARM大型机)

百度2015面试题:

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

小端字节序: 数据的低位字节存储在低地址处 高位字节存储在高地址处

思路:

  • 自己的思路:

    通过一个值0x11223344 存储为int变量 再创建一个字符数组char[4] 用一个字符指针char* 指向int变量 逐个字节将内容放入字符数组当中 最终检验字符数组的首元素是否为0x44 如果是 就为小端法 如果不是 那么就是大端法

  • 优秀思路:

    直接用一个最简单的值0x00000001 int变量 用char* 指向这个变量 解引用得到最低的一个字节 如果这个字节是内容为1 那么就是小端法 如果不是 那么就是大端法 (代码实现起来更简单)

代码:

int check_sys2()
{

    //更简单的一个方式
    int a = 1;
    //对比第一个字节的内容就可以了 如果第一个字节是1 就是小端 如果第一个字节是0 那就是大端
    char firstByte = *(char*)&a; //指定引用一个字节的内容 用char*强制类型转换
    if (firstByte) return 1;
    else return 0;
}

//自己实现的代码
void check_sys()
{
    //百度面试题: 讲解一下什么是大端和小端存储 -- 小端 低位字节放在低地址处 
    //设计一个程序来说明当前机器是大端还是小端
    int t = 0x11223344;
    char arr[4];
    char* p = &t;
    for (int i = 0; i < 4; i++)
    {
        arr[i] = *(p + i);
        //地址值占位符要用%p
        printf("char arr[%d],地址:%p,值为%x\n", i, p + i, arr[i]);
    }
    if (arr[3] == 0x44) printf("当前机器是大端法进行数据存储");
    else if (arr[3] == 0x11) printf("当前机器是小端法进行数据存储");
    //char arr[0], 地址:273fa08, 值为44
    //char arr[1], 地址:273fa09, 值为33
    //char arr[2], 地址:273fa0a, 值为22
    //char arr[3], 地址:273fa0b, 值为11

}

整数类型中 默认为有符号 前面加上unsigned关键字才为无符号

有符号 符号位+数值位 无符号 全部为数值位

10000000 被定义为-128 为 -127-1

有符号char -128~127

无符号char 0~255

考察: 数据的无意溢出造成意外的输出结果

截屏2024-07-29 15.54.44.png

截屏2024-07-29 15.55.33.png

        10000000 00000000 00000000 00010100
        11111111 11111111 11111111 11101011
        11111111 11111111 11111111 111101100//-20补码
        00000000 00000000 00000000 000001010//10补码
        11111111 11111111 11111111 111110110//相加结果的补码形式
        10000000000000000000000000001010//-10

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

浮点数 就是数学中的小数 123.45-->12.345* 10^1-->1.2345* 10^2 小数点可以浮动 就是浮点数

整型家族的类型表示范围 limits.h

浮点数: float.h

浮点数存储的规则 :IEEE754

截屏2024-07-29 16.04.34.png

截屏2024-07-29 16.08.28.png

S: 符号位 0表示正数 1表示负数 1位

E: 科学技术法的2的指数部分 8位

在内存当中的指数部分表示需要 真值+127(bias) bias的计算公式为2^(E的位数-1)-1 这是为了兼顾指数部分出现负数的情况

指数位全为0的情况 表示极小的数 此时M为0.xxxx 指数部分为-127

指数为全为1的情况 表示极大的数 此时指数部分为128 2^128

其他情况正常计算即可 E-127得到真实的指数

M:

截屏2024-07-29 16.16.58.png

一个例子:
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;
}

输出的结果为:

截屏2024-07-29 16.18.20.png 解释:

首先是创建一个int类型的变量 值为9

在内存当中为:

00000000 00000000 00000000 00001001
0 00000000 00000000000000000001001 //E全为0 %.f的精度只到小数点后六位 无法表示 所以为0

如果按照float类型存入9.0

那么在内存当中的存储形式为:

0 10000010 00100000000000000000000
01000001000100000000000000000000//如果按照整数的规则解引用 是一个很大的值 1,091,567,616