数据在内存中的存储

一、整数在内存中的存储:原码、反码与补码

整数是编程中最常用的数据类型之一,但其在内存中的存储并非简单的二进制直接转换,而是涉及原码、反码和补码三种表示形式。

1. 三种表示形式的定义

整数的二进制表示有原码、反码和补码三种,均包含符号位数值位

  • 符号位:0 表示 “正”,1 表示 “负”,位于数值位的最高位。
  • 数值位:除符号位外的其余部分,用于表示数值大小。

2. 正整数与负整数的差异

  • 正整数:原码、反码、补码完全相同。
    例如:整数5的二进制原码为00000000 00000000 00000000 00000101(32 位),反码和补码与之一致。

  • 负整数:三种形式不同,转换规则如下:

    • 原码:直接将数值按正负翻译为二进制(符号位为 1)。
      例如:-5的原码为10000000 00000000 00000000 00000101
    • 反码:符号位不变,其余位按位取反。
      例如:-5的反码为11111111 11111111 11111111 11111010
    • 补码:反码加 1。
      例如:-5的补码为11111111 11111111 11111111 11111011

3. 为什么内存中存储补码?

计算机系统中,整数一律以补码存储,原因有三:

  • 符号位与数值位可统一处理;
  • 加法和减法可统一运算(CPU 只有加法器);
  • 补码与原码的转换规则一致,无需额外硬件电路。

二、大小端字节序:数据的 “排列顺序”

当数据以多字节(如 int、long)存储时,字节的排列顺序会影响读取结果,这就是 “字节序” 问题,分为大端和小端两种模式。

1. 大端与小端的定义

  • 大端字节序:数据的低位字节存于内存高地址,高位字节存于内存低地址。
  • 小端字节序:数据的低位字节存于内存低地址,高位字节存于内存高地址。

2. 为什么存在字节序差异?

计算机以字节为基本存储单位,对于超过 1 字节的数据(如 16 位 short、32 位 int),需要规定字节排列顺序。这一差异源于处理器架构设计:

  • x86 架构(如 PC)采用小端模式;
  • KEIL C51(嵌入式)采用大端模式;
  • 部分 ARM 处理器可通过硬件切换模式。

3. 如何判断当前机器的字节序?

通过代码可快速判断字节序,核心思路是利用 “多字节数据的低地址字节值”:

方法 1:指针转换
#include <stdio.h>

int check_sys() 
{
    int i = 1;
    //取i的地址,转换为char*,仅访问第一个字节
    return *(char*)&i; 
}

int main() 
{
    if (check_sys() == 1) 
    {
        printf("小端\n"); //小端中,1的低字节(0x01)存在低地址
    } 
    else 
    {
        printf("大端\n"); //大端中,1的低字节(0x01)存在高地址
    }
    return 0;
}
方法 2:联合体(共用内存)
#include <stdio.h>

int check_sys() 
{
    union 
    {
        int i;
        char c;
    } un;
    un.i = 1;
    return un.c; //联合体中i和c共用内存,c取低地址字节
}

 

三、浮点数的存储:IEEE 754 标准

浮点数(如 float、double)的存储规则与整数完全不同,遵循 IEEE 754 国际标准。

1. 浮点数的表示形式

任意二进制浮点数可表示为:V=(−1)S×M×2E

  • S:符号位(0 为正,1 为负);
  • M:有效数字(1 ≤ M < 2,形如 1.xxxxxx);
  • E:指数位(可正可负)。

2. 内存存储结构

  • 32 位 float:1 位 S + 8 位 E + 23 位 M;
  • 64 位 double:1 位 S + 11 位 E + 52 位 M。

3. 存储细节:M 和 E 的特殊处理

有效数字 M
  • 由于 M 恒为 1.xxxxxx,存储时省略首位 1,仅存小数部分(节省 1 位空间)。例如,1.001 存储为 001(补满 23 位)。
指数 E
  • 存储时:E 为无符号整数,需加 “偏移值”(32 位加 127,64 位加 1023)。例如,E=3 时,32 位存储为 3+127=130(0x82)。
  • 读取时
    • 若 E 不全为 0 且不全为 1:真实值 = E - 偏移值;
    • 若 E 全为 0:真实值 = 1 - 偏移值(M 为 0.xxxxxx,表示接近 0 的数);
    • 若 E 全为 1:M 全 0 时表示 ± 无穷大。

4. 整数与浮点数的存储差异示例

为什么int n = 9float* pFloat = &n的打印结果不同?

  • 整数 9的二进制为00000000 00000000 00000000 00001001,以浮点数解析时:
    S=0,E=0(全 0),M=0.000...0001001,结果为接近 0 的极小值(打印为 0.000000)。

  • 浮点数 9.0的存储:
    9.0 的二进制为 1001.0 = 1.001×2³,因此 S=0,M=001(补 20 个 0),E=3+127=130(10000010)。
    内存二进制为0 10000010 00100000000000000000000,以整数解析时为 1091567616。

 

总结

数据在内存中的存储是程序运行的基础:

  • 整数通过补码存储,统一符号位与数值位的处理;
  • 字节序决定多字节数据的排列顺序,需根据架构适配;
  • 浮点数遵循 IEEE 754 标准,通过 S、M、E 的组合实现灵活表示。

理解这些规则,能帮助我们规避很多底层 bug(如字节序错误、类型转换异常),更深入地掌握编程本质。

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值