尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

深入理解C语言:数据在内存中的存储(整数、大小端、浮点数)

深入理解C语言:数据在内存中的存储(整数、大小端、浮点数)
📅 发布时间:2026/7/11 2:51:58

1. 整数在内存中的存储

在C语言中,整数类型(如int、char、short、long)在内存中是以二进制的补码形式存储的。理解这一点对于处理位运算、类型转换和内存操作至关重要。

原码、反码、补码:

  • 原码:直接将数值按照正负号转换成二进制。最高位为符号位(0正1负)。
  • 反码:正数的反码与原码相同;负数的反码是原码符号位不变,其余位取反。
  • 补码:正数的补码与原码相同;负数的补码是其反码加1。

计算机使用补码存储整数,因为补码可以将减法运算统一为加法运算,简化了CPU的设计。

代码示例:查看整数的内存表示

#include <stdio.h> int main() { // 定义两个整数变量,分别存储正数和负数 int a = 10; // 十进制10,正数 int b = -10; // 十进制-10,负数 unsigned char *p; // 声明一个无符号字符指针,用于按字节访问内存 // 打印变量的十进制值 printf("a = %d\n", a); printf("b = %d\n", b); // 查看a在内存中的每个字节(十六进制) printf("a在内存中的字节(从低地址到高地址):"); // 将整型变量a的地址强制转换为unsigned char*类型,这样p就指向a的第一个字节(最低地址) p = (unsigned char *)&a; // 循环遍历a的每一个字节(sizeof(a)返回int类型占用的字节数,通常是4) for (int i = 0; i < sizeof(a); i++) { // %02x 表示以两位十六进制输出,不足两位前面补0 // p[i] 等价于 *(p + i),即访问第i个字节的内容 printf("%02x ", p[i]); } printf("\n"); // 查看b在内存中的每个字节(十六进制) printf("b在内存中的字节(从低地址到高地址):"); // 重新让p指向b的起始地址,准备读取b的字节 p = (unsigned char *)&b; for (int i = 0; i < sizeof(b); i++) { printf("%02x ", p[i]); } printf("\n"); return 0; }

运行结果(在小端模式下)可能如下:

a = 10 b = -10 a在内存中的字节(从低地址到高地址):0a 00 00 00 b在内存中的字节(从低地址到高地址):f6 ff ff ff

解释:0a 00 00 00是10的补码(小端存储,低位在前)。f6 ff ff ff是-10的补码。

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

大小端(Endianness)是指多字节数据在内存中存储的字节顺序。

  • 小端模式(Little Endian):数据的低位字节存储在内存的低地址处,高位字节存储在高地址处。x86、ARM(通常)采用小端。
  • 大端模式(Big Endian):数据的高位字节存储在内存的低地址处,低位字节存储在高地址处。网络字节序、PowerPC等采用大端。

例如,一个4字节的整数0x12345678:

  • 小端存储(地址从低到高):78 56 34 12
  • 大端存储(地址从低到高):12 34 56 78

代码示例:判断当前系统的字节序

#include <stdio.h> // 方法1:使用联合体(union)判断字节序 int check_endian1() { // 定义一个联合体,包含一个int成员和一个char成员 // 联合体的所有成员共享同一块内存空间,大小由最大成员决定 union { int i; // 4字节整数 char c; // 1字节字符 } u; u.i = 1; // 将整数1赋值给联合体的int成员 // 由于联合体共享内存,u.c访问的是u.i的第一个字节(最低地址字节) // 如果这个字节的值是1,说明低位字节存储在低地址,是小端模式 // 如果这个字节的值是0,说明高位字节存储在低地址,是大端模式 return u.c == 1; } // 方法2:使用指针判断字节序 int check_endian2() { int num = 1; // 定义一个整数1 // 将int类型变量的地址强制转换为char*类型指针 // 这样可以通过指针按字节访问内存 char *p = (char *)&num; // 解引用指针,获取num的第一个字节(最低地址字节)的值 // 原理与方法1相同:如果第一个字节是1,则为小端;如果是0,则为大端 return *p == 1; } int main() { // 调用判断函数,根据返回值输出系统字节序 if (check_endian1()) { printf("当前系统为小端模式(Little Endian)\n"); } else { printf("当前系统为大端模式(Big Endian)\n"); } // 直观展示一个整数的字节存储顺序 int x = 0x12345678; // 定义一个十六进制整数,便于观察字节顺序 // 将x的地址转换为unsigned char*,用于按字节访问 unsigned char *ptr = (unsigned char *)&x; printf("整数 0x%x 在内存中的字节顺序(从低地址到高地址):\n", x); // 循环遍历x的每一个字节 for (int i = 0; i < sizeof(x); i++) { // 输出每个字节的十六进制表示 // ptr[i] 访问第i个字节,i=0对应最低地址字节 printf("%02x ", ptr[i]); } printf("\n"); return 0; }

运行结果(在常见x86系统上):

当前系统为小端模式(Little Endian) 整数 0x12345678 在内存中的字节顺序(从低地址到高地址): 78 56 34 12

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

C语言中的浮点数(float、double)遵循IEEE 754标准在内存中存储。以单精度浮点数(float,32位)为例:

  • 1位符号位(S):0表示正数,1表示负数。
  • 8位指数位(E):表示2的幂次,采用移码表示(实际指数 = E - 127)。
  • 23位尾数位(M):表示有效数字的小数部分(隐含整数部分为1,除非是特殊值)。

浮点数的值计算公式为:(-1)^S * 1.M * 2^(E-127)

代码示例:剖析浮点数的内存布局

#include <stdio.h> #include <stdint.h> // 联合体用于将float的位模式解释为整数,便于按位查看 typedef union { float f; uint32_t u; } float_union; void print_float_bits(float val) { float_union fu; fu.f = val; uint32_t bits = fu.u; // 提取符号位、指数位、尾数位 uint32_t sign = (bits >> 31) & 0x1; uint32_t exponent = (bits >> 23) & 0xFF; uint32_t mantissa = bits & 0x7FFFFF; // 23位 printf("浮点数: %f\n", val); printf("十六进制: 0x%08x\n", bits); printf("符号位 S: %u (%s)\n", sign, sign ? "负数" : "正数"); printf("指数位 E: %u (实际指数 = %d)\n", exponent, (int)exponent - 127); printf("尾数位 M: 0x%06x\n", mantissa); printf("二进制: "); for (int i = 31; i >= 0; i--) { printf("%d", (bits >> i) & 1); if (i == 31 || i == 23) printf(" "); // 分隔符 } printf("\n\n"); } int main() { float f1 = 6.5f; float f2 = -3.75f; float f3 = 0.0f; print_float_bits(f1); print_float_bits(f2); print_float_bits(f3); // 验证一个特殊值:NaN(非数) float_union nan_val; nan_val.u = 0x7fc00000; // 典型的NaN表示 printf("NaN 示例: 0x%08x 对应的浮点数值: %f\n", nan_val.u, nan_val.f); return 0; }

运行结果示例:

浮点数: 6.500000 十六进制: 0x40d00000 符号位 S: 0 (正数) 指数位 E: 129 (实际指数 = 2) 尾数位 M: 0x500000 二进制: 0 10000001 10100000000000000000000 浮点数: -3.750000 十六进制: 0xc0700000 符号位 S: 1 (负数) 指数位 E: 128 (实际指数 = 1) 尾数位 M: 0x700000 二进制: 1 10000000 11100000000000000000000 浮点数: 0.000000 十六进制: 0x00000000 符号位 S: 0 (正数) 指数位 E: 0 (实际指数 = -127) 尾数位 M: 0x000000 二进制: 0 00000000 00000000000000000000000 NaN 示例: 0x7fc00000 对应的浮点数值: nan

三种存储方式对比

下表横向对比了整数存储(补码)、大小端字节序和浮点数存储(IEEE 754)的核心要点:

对比维度整数存储(补码)大小端字节序浮点数存储(IEEE 754)
存储格式二进制补码形式:正数与原码相同,负数为反码加1字节排列顺序:小端(低位在前)或大端(高位在前)符号位(S) + 指数位(E,移码) + 尾数位(M)
主要目的/优势统一加减法运算,简化CPU设计;解决0的表示唯一性问题定义多字节数据在内存中的字节顺序,不同架构有不同约定科学计数法的二进制实现,平衡表示范围与精度,支持特殊值(NaN、无穷)
典型应用场景所有整数运算、位操作、类型转换、内存直接读写网络通信(需统一字节序)、跨平台数据交换、文件格式解析科学计算、图形处理、金融计算、任何需要小数或极大/极小数值的场景
需要注意的陷阱溢出问题、有符号/无符号转换时的符号扩展、移位操作的未定义行为跨平台/跨网络时字节序转换(htonl/ntohl)、直接内存拷贝可能导致数据错乱精度损失(如0.1无法精确表示)、比较浮点数应使用误差范围、特殊值(NaN、无穷)处理

总结:

  • 整数存储使用补码,便于运算。
  • 大小端影响多字节数据的字节顺序,编程时需要注意(尤其是网络通信和文件读写)。
  • 浮点数存储遵循IEEE 754标准,理解其内存布局有助于避免精度问题和进行底层优化。

相关新闻

  • 【MicroPython编程-ESP32篇:设备驱动】-TEMT6000环境光传感器驱动
  • Solar Energy (IF 7.188) 2024年热点解读:从光伏材料到电网整合的3大技术趋势
  • 广州积家回收价格查询及各大平台实测排行(2026年7月最新数据) - 积家官方售后服务中心

最新新闻

  • 2026上海企业布局生成式搜索:GEO系统要点与选择核验指南 - 企智芯
  • 锂离子电池过压保护与BQ29200智能平衡方案解析
  • 车载HMI设计规范解析:12.3英寸屏1920x720px适配与3秒交互原则
  • 1 年国内预科直通多国本科!西安交通大学 IFC 国际本科预科项目优势一览 - 资讯纵览
  • 爱回收买二手靠谱吗?618战报给了我判断依据 - 资讯纵览
  • 2026年7月最新郑州劳力士官方售后服务热线与网点地址查询 - 劳力士官方服务中心

日新闻

  • OpenClaw本地部署:一键直连微信的私有化AI Agent实战指南
  • Kubernetes 系列【10】控制器:ReplicaSet(副本集)
  • 怎么寄快递才能便宜呢?2026年7月寄快递省钱攻略 - 生活情报姬

周新闻

  • 基于YOLOv12的番茄成熟度智能检测系统开发
  • 终极RimWorld模组管理指南:用RimSort告别模组冲突烦恼
  • AI Agent框架开发:从理论到实践的完整指南

月新闻

  • 2026年6月公司网站搭建最新热门渠道测评:四大低成本/零代码平台对比+避坑
  • 【Linux】Linux arm 编译QT程序,出现expected “}“报错
  • 【MATLAB例程】四基站二维AOA定位与距离辅助增强对比仿真。基于角度观测和测距修正的固定目标平面定位精度分析

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号