数据在内存中存储(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.mzph.cn/diannao/76482.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python爬虫第2节-网页基础和爬虫基本原理

目录 一、网页基础 1.1 网页的组成 1.2 网页的结构 1.3 节点树及节点间的关系 1.4 选择器 二、爬虫的基本原理 2.1 爬虫概述 2.2 能抓怎样的数据 2.3 JavaScript 渲染页面 一、网页基础 使用浏览器访问网站时&#xff0c;我们会看到各式各样的页面。你是否思考过&…

python-leetcode 64.在排序数组中查找元素的第一个和最后一个位置

题目&#xff1a; 给一个按照非递减顺序排列的整数数组nums,和一个目标值target,请找出给定目标值在数组中的开始位置和结束位置。 如果数组中不存在目标值target,返回[-1,-1] 方法一&#xff1a;二分查找 直观的思路肯定是从前往后遍历一遍。用两个变量记录第一次和最后一次…

分享一些新版GPT-4o使用方式!能多模态生图!

目前GPT-4o的整体测评&#xff0c;真的很惊艳。 不知道又有多少人因为OpenAI的这次更新而失业&#xff0c;当然只要AI用得好&#xff0c;会有更多人因之而受益&#xff01;很多人表示不知道怎么用&#xff0c;对于门外汉来说&#xff0c;4o似乎有点高端。 今天就给大家介绍几…

软件工程面试题(二十四)

1、连接池的原理 j2ee 服务器启动时会建立一定数量的池连接,并一直维持不少于此数量的池连接。当客户端程序需要连接时,吃驱动程序会返回一个未使用的池连接并将其标记为忙。如果当前 没有空闲连接,池驱动就建立一定新的 连接 2、用javascript编写脚本小程序,实现点击全选…

Android:Dialog的使用详解

Android中Dialog的使用详解 Dialog&#xff08;对话框&#xff09;是Android中常用的UI组件&#xff0c;用于临时显示重要信息或获取用户输入。 1. 基本Dialog类型 1.1 AlertDialog&#xff08;警告对话框&#xff09; 最常用的对话框类型&#xff0c;可以设置标题、消息、…

arinc818 fpga单色图像传输ip

arinc818协议支持的常用线速率如下图 随着图像分辨率的提高&#xff0c;单lane的速率无法满足特定需求&#xff0c;一种方式是通过多个LANE交叉的去传输图像&#xff0c;另外一种是通过降低图像的带宽&#xff0c;即通过只传单色图像达到对应的效果 程序架构如下图所示&#x…

透视投影(Perspective projection)与等距圆柱投影(Equirectangular projection)

一、透视投影 1.方法概述 Perspective projection&#xff08;透视投影&#xff09;是一种模拟人眼观察三维空间物体时的视觉效果的投影方法。它通过模拟观察者从一个特定视点观察三维场景的方式来创建二维图像。在透视投影中&#xff0c;远处的物体看起来比近处的物体小&…

三.微服务架构中的精妙设计:服务注册/服务发现-Eureka

一.使用注册中心背景 1.1服务远程调用问题 服务之间远程调⽤时, 我们的URL是写死的 String url "http://127.0.0.1:9090/product/" orderInfo.getProductId(); 缺点&#xff1a; 当更换机器, 或者新增机器时, 这个URL就需要跟着变更, 就需要去通知所有的相关服…

FPGA实现4K MIPI视频解码H265压缩网络推流输出,基于IMX317+VCU架构,支持4K60帧,提供工程源码和技术支持

目录 1、前言工程概述免责声明 2、相关方案推荐我已有的所有工程源码总目录----方便你快速找到自己喜欢的项目我这里已有的 MIPI 编解码方案我这里已有的视频图像编解码方案 3、详细设计方案设计框图FPGA开发板IMX317摄像头MIPI D-PHYMIPI CSI-2 RX Subsystem图像预处理Sensor …

Ollama+open-webui搭建私有本地大模型详细教程

Ollamaopen-webui搭建私有本地大模型详细教程 1. 什么是 Ollama&#xff1f; 1.1. Ollama 简介 ​ Ollama 是一个轻量级的 AI 模型运行时&#xff0c;专注于简化 AI 模型的部署和使用。它支持多种预训练模型&#xff08;如 Llama、Vicuna、Dolly 等&#xff09;&#xff0c;…

解决Centos7集成IDEA报git版本太低问题

Centos 7 服务器上默认安装的 Git 是 1.8.3.1 版本的 与最新的IDEA已无法匹配&#xff0c;需要更新 首先&#xff0c;卸载老版本 sudo yum -y remove git sudo yum -y remove git-*添加 End Point 到 CentOS 7 仓库 sudo yum -y install https://packages.endpointdev.com/r…

Qt常用宏定义判断大全

Qt 提供了一系列预定义宏用于判断 Qt 版本、操作系统平台、编译器特性等。这些宏在跨平台开发中非常有用。 1. Qt 版本判断宏 // 检查Qt版本 #if QT_VERSION > QT_VERSION_CHECK(5, 15, 0)// Qt 5.15.0及以上版本特有代码 #endif// 常用版本判断 #if QT_VERSION > QT_V…

实战 | 餐厅点餐小程序技术解析:SpringBoot + UniApp 高效开发指南

&#x1f5a5;️ 一、系统架构概览 1.1 技术选型 为了确保开发效率和系统稳定性&#xff0c;我们采用以下技术栈&#xff1a; 模块技术选型后台服务SpringBoot MyBatis-Plus MySQL用户端&#xff08;点餐小程序&#xff09;UniApp&#xff08;Vue 语法&#xff09;师傅端&…

实现在Unity3D中仿真汽车,而且还能使用ros2控制

文章目录 前言&#xff08;Introduction&#xff09;搭建开发环境&#xff08;Setup Development Environment&#xff09;在window中安装Unity&#xff08;Install Unity in window&#xff09;创建Docker容器&#xff0c;并安装相关软件&#xff08;Create Docker containers…

华为配置篇-BGP实验

BGP 一、简述二、常用命令总结三、实验 一、简述 IBGP 水平分割&#xff1a;从一个 IBGP 对等体学到的路由&#xff0c;不会再通告给其他的 IBGP 对等体。在一个 AS 内部&#xff0c;路由器之间通过 IBGP 交换路由信息。如果没有水平分割机制&#xff0c;当多个路由器之间形成…

Python视频标签工具详解:基于wxPython和FFmpeg的实现

在当今数字媒体时代&#xff0c;视频内容的管理和标记变得越来越重要。无论是研究人员需要对实验视频进行时间点标记&#xff0c;教育工作者需要对教学视频添加注释&#xff0c;还是个人用户希望对家庭视频进行分类整理&#xff0c;一个高效的视频标签工具都是不可或缺的。本文…

国产三维CAD「皇冠CAD」在汽车零部件领域建模教程:刹车片

本教程深度融合三维皇冠CAD&#xff08;CrownCAD&#xff09;的MBD&#xff08;Model-Based Definition&#xff09;设计理念&#xff0c;通过参数化建模、智能约束管理、动态装配验证等功能&#xff0c;实现数据驱动设计&#xff0c;精准解决了汽车制动系统中精密制动组件的设…

C#从入门到精通(3)

目录 第九章 窗体 &#xff08;1&#xff09;From窗体 &#xff08;2&#xff09;MDI窗体 &#xff08;3&#xff09;继承窗体 第十章 控件 &#xff08;1&#xff09;控件常用操作 &#xff08;2&#xff09;Label控件 &#xff08;3&#xff09;Button控件 &…

关于跨域与.NET的处理方案

在 Web 开发里&#xff0c;浏览器的同源策略是一项关键的安全机制。同源指的是两个 URL 的协议、域名和端口都相同。当浏览器从一个源&#xff08;域名、协议、端口&#xff09;的网页去请求另一个源的资源时&#xff0c;就会产生跨域问题。例如&#xff0c;从 http://www.exam…

react 15-16-17-18各版本的核心区别、底层原理及演进逻辑的深度解析--react18

React 18 是一次重大的版本升级&#xff08;发布于2022年&#xff09;&#xff0c;引入了并发渲染&#xff08;Concurrent Rendering&#xff09; 和一系列新特性&#xff0c;旨在提升应用性能、用户体验和开发灵活性。 一、核心新特性 并发模式&#xff08;Concurrent Mode&a…