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

【2个月 C 语言从入门到精通:零基础系统教程】第十三讲:数据在内存中的存储

文章目录

  • 前言
  • 1. 整数在内存中的存储
  • 2. 大小端字节序和字节序判断
    • 2.1 什么是大小端?
    • 2.2 为什么有大小端?
    • 2.3 练习
      • 2.3.1 练习1
      • 2.3.2 练习2
        • 最关键的坑:printf 与 %d(整型提升)
        • 为什么 b (signed char) 打印出 -1?
        • 为什么 c (unsigned char) 打印出 255?
        • 为什么 a (char) 是不确定的?
      • 2.3.3 练习3
        • 第一步:8位内存存储
        • 第二步:整型提升与格式说明符
        • 第三步:数学计算(算出结果)
        • 核心要点总结
      • 2.3.4 练习4
        • 第一步:变量赋值(溢出)
        • 第二步:整型提升与符号扩展(“大变身”)
        • 第三步:%u 无符号打印
        • 核心要点总结
      • 2.3.5 练习5
        • 1. 核心前提:char 的取值范围
        • 2. for 循环与二进制溢出(回绕)
        • 3. strlen 的工作原理
        • 4. 最终结果
        • 5. 深入理解:为什么是255而不是256?
        • 6. 扩展思考:如果数组更大呢?
        • 7. 实际应用中的注意事项
        • 8. 总结要点
      • 2.3.6 练习6
      • 2.3.7 练习7
        • 1. 环境前提:小端字节序 & X86环境
        • 2. 第一个输出:ptr1[-1]
        • 3. 第二个输出(难点):*ptr2
        • 4. 图解 *ptr2 到底读了什么
        • 5. 最终数字的由来
  • 3. 浮点数的存储
    • 3.1 浮点数存储
    • 3.2 IEEE 754 对有效数字 M 和指数 E 的特殊规定
    • 3.3 浮点数的三种存储情况详解
      • 🚨 1. 浮点数在内存中的根本结构(以 32 位 float 为例)
      • ⚙️ 情况一:规格化数(最常见的数字)
      • ⚙️ 情况二:非规格化数(接近 0 的小数)
      • ⚙️ 情况三:特殊值(无穷大和 NaN)
      • 总结对比表
    • 3.4 题目详解
      • 示例代码
      • 第一部分:写入整数,按浮点数读取
        • 1. 整数 9 在内存中的存储
        • 2. 强制类型转换
        • 3. 按浮点数规则解读
      • 第二部分:写入浮点数,按整数读取
        • 1. 写入浮点数 9.0
        • 2. 按整数规则读取
        • 3. 验证浮点数读取
      • 内存变化示意图
      • 核心要点总结
      • 扩展思考

前言

在C/C++编程中,理解数据在内存中的存储方式是深入掌握底层原理的关键。无论是简单的整数运算,还是复杂的浮点数处理,最终都需要转化为二进制形式在计算机内存中进行存储和操作。然而,许多开发者在面对类型转换、字节序、整型提升、浮点数精度等问题时,常常感到困惑,甚至写出存在潜在风险的代码。

本文旨在系统性地解析C/C++中数据在内存中的存储机制,从最基础的整数原码、反码、补码表示,到复杂的大小端字节序,再到浮点数的IEEE 754标准存储格式。通过大量实际代码示例和逐步分析,我们将深入探讨:

  1. 整数存储原理:为什么计算机使用补码?原码、反码、补码之间如何转换?
  2. 大小端字节序:什么是大端和小端?为什么会有这两种存储模式?如何判断当前系统的字节序?
  3. 整型提升与类型转换:当char类型用%d打印时发生了什么?为什么unsigned char和signed char会有不同的结果?
  4. 浮点数存储细节:IEEE 754标准如何表示浮点数?规格化数、非规格化数、特殊值(无穷大、NaN)有什么区别?
  5. 经典案例分析:通过多个练习题目,深入理解数据存储的实际应用和潜在陷阱。

无论你是正在学习C/C++的初学者,还是希望深入理解计算机底层原理的中级开发者,本文都将为你提供清晰、系统的知识体系。通过阅读本文,你将能够:

  • 准确理解数据在内存中的二进制表示
  • 掌握类型转换和整型提升的底层机制
  • 熟练分析涉及字节序和内存对齐的问题
  • 深入理解浮点数精度问题和特殊值的处理
  • 编写更加健壮、可移植的底层代码

让我们开始这段探索内存存储奥秘的旅程吧!

1. 整数在内存中的存储

在讲解操作符的时候,我们就讲过了下面的内容:

整数的二进制表示方法有三种,即:原码、反码和补码。

有符号的整数,三种表示方法均有符号位和数值位两部分。符号位都是用0表示“正”,用1表示“负”,最高位的一位是被当做符号位,剩余的都是数值位。

  • 正整数的原、反、补码都相同。
  • 负整数的三种表示方法各不相同。
    • 原码:直接将数值按照正负数的形式翻译成二进制得到的就是原码。
    • 反码:将原码的符号位不变,其他位依次按位取反就可以得到反码。
    • 补码:反码 + 1 就得到补码。

对于整型来说:数据存放在内存中其实存放的是二进制的补码。

为什么呢?

在计算机系统中,数值一律用补码来表示和存储。原因在于:

  1. 使用补码,可以将符号位和数值域统一处理;
  2. 同时,加法和减法也可以统一处理(CPU只有加法器);
  3. 此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路。

2. 大小端字节序和字节序判断

当我们了解了整数在内存中存储后,我们调试看⼀个细节:

2.1 什么是大小端?

其实超过一个字节的数据在内存中存储的时候,就有存储顺序的问题,按照不同的存储顺序,我们分为大端字节序存储小端字节序存储,下面是具体的概念:

  • 大端(存储)模式:是指数据的低位字节内容保存在内存的高地址处,而数据的高位字节内容,保存在内存的低地址处
  • 小端(存储)模式:是指数据的低位字节内容保存在内存的低地址处,而数据的高位字节内容,保存在内存的高地址处

上述概念需要记住,方便分辨大小端。

2.2 为什么有大小端?

为什么会有大小端模式之分呢?这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为 8 bit 位。但是在 C 语言中除了 8 bit 的char之外,还有 16 bit 的short型,32 bit 的long型(要看具体的编译器)。另外,对于位数大于 8 位的处理器,例如 16 位或者 32 位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如何将多个字节安排的问题。因此就导致了大端存储模式小端存储模式

例如:一个 16 bit 的short型变量x,在内存中的地址为0x0010x的值为0x1122,那么0x11为高字节,0x22为低字节。

  • 对于大端模式,就将0x11放在低地址中,即0x0010中,0x22放在高地址中,即0x0011中。
  • 小端模式,刚好相反。

我们常用的 X86 结构是小端模式,而 KEIL C51 则为大端模式。很多的 ARM、DSP 都为小端模式。有些 ARM 处理器还可以由硬件来选择是大端模式还是小端模式。

2.3 练习

2.3.1 练习1

请简述⼤端字节序和⼩端字节序的概念,设计⼀个⼩程序来判断当前机器的字节序。(10分)–百度笔试题


代码展示

intmain(){inta=1;if(*(char*)&a==1){printf("小端\n");}else{printf("大端\n");}return0;}//代码2intcheck_sys(){inta=1;if(*(char*)&a==1)return1;//小端elsereturn0;//大端}//代码3intcheck_sys(){inta=1;return(*(char*)&a);}intmain(){if(check_sys()==1){printf("小端\n");}else{printf("大端\n");}return0;}

2.3.2 练习2

思考一下为什么会出新这种结果

详细讲解

这段代码定义了三个字符类型的变量,并赋了同样的值-1

signedcharb=-1;// b 在内存中是:11111111 (8位,代表 -1)unsignedcharc=-1;// c 在内存中也是:11111111 (但代表 255)chara=-1;// a 在内存中是:11111111 (但代表什么取决于编译器)

在计算机内存中,整数是以补码形式存储的。对于 8 位(1字节)的char类型,-1的二进制补码是11111111

注意:标准 C/C++ 中,默认的char到底是有符号(signed char)还是无符号(unsigned char)是由编译器决定的。所以变量a的值存在不确定性。

最关键的坑:printf 与 %d(整型提升)

代码中使用了:

printf("a = %d, b = %d, c = %d\n"
http://www.gsyq.cn/news/1546225.html

相关文章:

  • Ant Design 紧凑模式实战指南:如何节省40%屏幕空间提升信息密度?
  • 赤峰市黄金回收+白银回收+铂金回收+彩金回推荐收门店 本地靠谱店铺指南及地联系方式址和 - 大熊猫898989
  • FigmaCN完整指南:3分钟免费实现Figma中文界面的终极解决方案
  • 工业级AI模型落地避坑指南:数据质量、特征工程与线上监控实战
  • 干货指南:推荐好用的管体包封板品牌 - myqiye
  • TikTok加密参数逆向实战:从SSL Pinning绕过到算法黑盒调用
  • 多Agent图片提示词提取:从架构设计到工程实现
  • TradingView股票筛选器Python包终极指南:三步实现自动化交易分析
  • 顶拉管生产商哪家性价比高?同盛管业揭秘 - mypinpai
  • 达州市黄金回收+白银回收+铂金回收+彩金回推荐收门店 本地靠谱店铺指南及地联系方式址和 - 大熊猫898989
  • 【知识库终极方案】传统 RAG、LightRAG、GitNexus、graphify、Understand Anything、CodeGraph 横向对比
  • STM32F103 RS485 Modbus从机工程:带汉字LCD显示与全外设驱动支持
  • Cursor Free VIP终极指南:永久免费解锁AI编程助手完整功能
  • 腾讯Hunyuan3D-2.0:8GB显存实现实时3D生成
  • 告别文件下载:kkFileView一站式在线预览解决方案终极指南
  • Linux系统JDK安装与配置全攻略:从版本选择到生产环境部署
  • 9大网盘直链下载工具终极指南:一键获取真实下载地址的完整解决方案
  • 082、PCIE原生控制与中断:从一次诡异的设备失联说起
  • 保险理赔OCR实战:从技术选型到工程落地的全链路解析
  • 驯服电源尖峰:从BUCK/BOOST环路剖析到高di/dt噪声的实战抑制
  • 跨游戏引擎场景互通加载元宇宙技术设想
  • Qwen3-VL工业部署实战:前沿多模态大模型落地指南
  • 强双曲空间:从Gromov双曲性到边界结构与交叉比
  • 数据驱动型AI开发:从模型中心到数据主轴的范式迁移
  • 2026年6月靠谱的涂覆机企业推荐,常压灌胶机/视觉点胶机/三段式真空灌胶机/薄膜均匀涂覆机,涂覆机品牌怎么选择 - 品牌推荐师
  • SegFormer实战指南:显存优化与跨分辨率泛化
  • 如何让BT下载速度翻倍?每天更新的Tracker列表是你的终极解决方案
  • Win7蓝牙耳机驱动问题全解析:从诊断到安装的完整解决方案
  • 本地多模态RAG实战:ColPali+Llama 3.2 Vision离线文档理解
  • 2026年正规的景区推荐公司服务覆盖实力汇总 - myqiye