当前位置: 首页 > news >正文

数据在内存中存储(C语言)

文章目录

    • 前言
    • 一、整数在内存中的存储
      • 1.1 计算机存储数据的基本单位
        • 示例代码
      • 1.2 无符号整数的存储
      • 1.3 有符号整数的存储(补码)
        • 示例代码
    • 二、大小端字节序和字节序判断
      • 2.1 什么是大小端?
        • 示例代码
      • 2.2 为什么会有大小端?
      • 2.3 字节序的判断
    • 三、浮点数在内存中的存储
      • 3.1 IEEE 754 浮点数表示法
        • 示例代码(单精度浮点数)
      • 3.2 浮点数存储结构
      • 3.3 浮点数的存储和读取过程
        • 存储过程:
        • 读取过程:
    • 总结

前言

在计算机的世界里,所有数据最终都要存储到内存中,而内存是以 字节(Byte) 为单位进行存储的。不同类型的数据在内存中的存储方式可能不一样,甚至可能会涉及字节顺序(大小端)。理解这些存储原理不仅能帮助我们掌握计算机底层原理,还能提高编程和调试能力。

本文将带你从 整数大小端浮点数 三个方面,深入浅出地介绍数据在内存中的存储方式,并通过详细的示例代码加以说明。
在这里插入图片描述


一、整数在内存中的存储

整数(如 int 类型)的存储方式与其 二进制表示 密切相关。下面介绍计算机存储数据的基本单位,以及无符号整数和有符号整数(使用补码)的存储方式。

1.1 计算机存储数据的基本单位

计算机的存储是 二进制 的,最小的存储单位是 位(bit)。每 8 个 bit 组成 1 个字节(Byte)。

例如:

  • 1 bit:取值 01
  • 1 Byte = 8 bits:例如,00000000 表示十进制 000000001 表示十进制 1

计算机通常以 字节(Byte) 为单位存储数据,而整数通常占用 多个字节

示例代码
#include <stdio.h>

int main() {
    int num = 5;
    printf("%d 在内存中的大小: %lu 字节\n", num, sizeof(num));
    return 0;
}

1.2 无符号整数的存储

无符号整数(unsigned int)只表示非负数,直接使用二进制表示。例如,假设 unsigned int 类型占 4 个字节(32 位):

十进制数二进制表示(32 位)
500000000 00000000 00000000 00000101
25500000000 00000000 00000000 11111111

可以看到,数值 5 存储为 00000101(低位在右,高位在左)。

1.3 有符号整数的存储(补码)

有符号整数(int)可以表示正数和负数。计算机通常采用 补码 来表示负数,这样可以使加减运算统一,并且只有唯一的零表示。

负数的补码计算过程:

  1. 将数值的绝对值转换为二进制原码。
  2. 对原码每一位取反(0 变 1,1 变 0)。
  3. 最后加 1,得到补码。
示例代码
#include <stdio.h>

int main() {
    int num = -5;
    printf("%d 在内存中的存储: ", num);
    unsigned char *p = (unsigned char *)&num;
    for (int i = 0; i < sizeof(num); i++) {
        printf("%02X ", p[i]);
    }
    printf("\n");
    return 0;
}

通过该示例,你可以看到 -5 在内存中的存储(二进制补码表示)。


二、大小端字节序和字节序判断

对于多字节数据(如 intfloat),它们在内存中的存储顺序依赖于 CPU 架构,通常分为大端和小端两种模式。

2.1 什么是大小端?

  • 大端(Big Endian):高位字节存储在低地址,低位字节存储在高地址。这种方式符合人类阅读习惯,从左到右依次递减。
  • 小端(Little Endian):低位字节存储在低地址,高位字节存储在高地址,便于计算机进行加法等运算(从最低有效位开始)。
示例代码
#include <stdio.h>

void print_bytes(int num) {
    unsigned char *p = (unsigned char *)&num;
    for (int i = 0; i < sizeof(num); i++) {
        printf("%02X ", p[i]);
    }
    printf("\n");
}

int main() {
    int num = 0x12345678;
    printf("内存中的存储顺序: ");
    print_bytes(num);
    return 0;
}

根据你的 CPU 架构,你可能会看到:

  • 大端模式:输出类似 12 34 56 78
  • 小端模式:输出类似 78 56 34 12

2.2 为什么会有大小端?

大小端的区别主要来源于计算机体系结构的不同:

  • 大端模式:最早由 IBM 等体系架构采用,数据按人类阅读习惯存储(高位在前)。
  • 小端模式:主要由 Intel 体系架构采用,便于在进行算术运算时从低位开始处理数据,简化了硬件设计。

2.3 字节序的判断

可以通过一个简单的 C 语言程序来判断当前系统的字节序:

#include <stdio.h>

int main() {
    int num = 1;
    if (*(char *)&num == 1) {
        printf("小端模式\n");
    } else {
        printf("大端模式\n");
    }
    return 0;
}

如果输出 “小端模式”,说明低位字节存储在低地址。


三、浮点数在内存中的存储

浮点数的存储采用 IEEE 754 标准,将浮点数拆分为符号位、指数位和尾数位。下面详细介绍 IEEE 754 浮点数表示法、存储结构以及存储和读取过程。

3.1 IEEE 754 浮点数表示法

IEEE 754 是国际通用的浮点数存储标准,主要分为两种格式:

  • 单精度浮点数(32 位)

    • 符号位(S):1 位,表示正负(0 表示正数,1 表示负数)。
    • 指数位(E):8 位,采用移码表示(偏移量为 127)。
    • 尾数位(M):23 位,存储有效数字,默认存在隐含的 1
  • 双精度浮点数(64 位)

    • 符号位(S):1 位
    • 指数位(E):11 位,偏移量为 1023。
    • 尾数位(M):52 位
示例代码(单精度浮点数)
#include <stdio.h>

void print_float(float num) {
    unsigned char *p = (unsigned char *)&num;
    for (int i = 0; i < sizeof(num); i++) {
        printf("%02X ", p[i]);
    }
    printf("\n");
}

int main() {
    float num = 3.14f;
    printf("3.14 在内存中的存储: ");
    print_float(num);
    return 0;
}

通过该示例,你可以看到 3.14 在内存中的字节序列,理解其 IEEE 754 格式的表示。

3.2 浮点数存储结构

以单精度浮点数为例,存储过程大致如下:

  1. 转换为二进制:将十进制数(例如 3.14)转换为二进制表示。
    例如 3.14 的二进制近似表示为 11.001001...

  2. 标准化:将二进制数调整为 1.xxxxx 的形式,同时记录指数。
    对于 3.14,标准化表示为 1.1001001... × 2^1

  3. 计算指数:将标准化指数加上偏移量(单精度偏移量为 127),得到最终的指数部分。
    对于上例:指数 1 + 127 = 128,其二进制表示为 10000000

  4. 处理尾数:舍去标准化表示中的隐含的 1,保留后面的有效位作为尾数。
    例如:尾数为 1001001...,填充到 23 位。

  5. 符号位:根据正负确定符号位(正数为 0,负数为 1)。

最终,3.14 会按照上述结构存储为 4 字节(32 位)的二进制数据。

3.3 浮点数的存储和读取过程

存储过程:
  1. 将十进制浮点数转换为二进制表示;
  2. 标准化成 1.xxx 的格式;
  3. 计算指数并加上偏移量;
  4. 提取尾数并构造 IEEE 754 格式;
  5. 将符号位、指数位和尾数位组合成最终的存储格式。
读取过程:
  1. 从内存中读取浮点数的 4 字节数据;
  2. 分析并提取符号位、指数位和尾数位;
  3. 将指数位减去偏移量(127)得到实际指数;
  4. 还原尾数(在前面补上默认的隐含 1);
  5. 根据符号位决定正负,最终还原为十进制浮点数。

总结

本文详细介绍了数据在内存中的存储方式,重点涵盖了:

  • 整数存储:理解无符号整数直接存储和有符号整数使用补码存储的原理。
  • 大小端字节序:了解大端与小端的概念、产生原因及判断方法。
  • 浮点数存储:通过 IEEE 754 标准,了解浮点数的符号位、指数位和尾数位的表示方法,以及存储与读取过程。

掌握这些知识,将帮助你更深入地理解计算机底层原理,并在调试和系统编程中更加得心应手。希望这篇博客能为你的学习提供实用的参考!

http://www.dtcms.com/a/108458.html

相关文章:

  • 杂篇-行业分类一二-2(通、专用设备制造,汽车制造)
  • (done) MIT6.824 Lecture 02 - RPC and Threads
  • stm32:sg90 和 mg90s舵机学习
  • Python----计算机视觉处理(Opencv:道路检测之提取车道线)
  • 好玩有趣的github开源项目分享(持续更新)
  • 【MySQL基础】 JSON函数入门
  • 代码随想录-动态规划18
  • 如何学习C++以及C++的宏观认知
  • AI:机器学习模型-线性回归
  • 清华大学:网络大模型NetGPT研究进展(2025)
  • 深入解析JavaScript混淆加密与Python逆向调用实战-题八
  • 蓝桥杯-算法基础-For循环
  • [CISSP] [5] 保护资产安全
  • Mybatis 如何自定义缓存?
  • UML 关系探秘:理论与实践双维度剖析
  • Cesium for Unreal 源码编译
  • php开发rest api,哪个框架最好
  • C# 窗体应用(.FET Framework) 与 visionpro 连接
  • Unity Final IK:下一代角色动画与物理交互的技术解析
  • 合合信息TextIn大模型加速器2.0:图表解析能力的横向测评
  • Ansible(1)—— Ansible 概述
  • Spring常见题
  • Go语言学习(15)结构体标签与反射机制
  • ES6(8) Fetch API 详解
  • C#:base 关键字
  • 铂卡梭 智能羽翼 AI 系统:交易科技的未来引擎
  • php8 match表达式使用教程
  • 软件重构与项目进度的矛盾如何解决
  • Node.js全局生效的中间件
  • pytorch中Dropout