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

C语言结构体中的内存对齐

C语言结构体内存对齐

在C语言编程中,结构体是一种非常重要的数据类型,它允许我们将不同类型的数据组合在一起。然而,当涉及到结构体在内存中的存储时,有一个关键的概念——内存对齐,这往往容易被忽视,但却对程序的性能和内存使用有着重要影响。

一、结构体大小计算的“理论”与“实际”差异

首先,我们可能会想当然地认为,结构体的大小就是其所有成员大小的简单相加。比如,有这样一个结构体:

struct studentinfo
{char name[128];int *p;short b;int c;unsigned int age;char sex[20];
};

理论上计算各成员大小之和:128 + 8 + 2 + 4 + 4 + 20 = 166字节(在64位系统中,指针int *p占8字节)。但实际通过sizeof运算符计算时,在64位系统下得到的结果是168字节,和理论值存在偏差。这是为什么呢?

二、内存对齐的原因

这就涉及到内存对齐了。计算机为了提高CPU的寻址效率,在存储数据时会进行内存对齐。一般来说,嵌入式系统多采用32位系统,CPU的地址总线是32位,为了提升CPU的工作效率,寻址通常以4字节为单位。当数据宽度不足4字节时,系统会默认提供4字节内存方便CPU寻址,这种方式就是字节对齐。

我们可以通过示意图来理解:
image

  • 地址未对齐的情形:CPU读取数据时可能需要多次读取,比如要读取一段数据,可能需要读取3次才能获取完整数据。
  • 地址已对齐的情形:CPU可以更少次数地读取到完整数据,比如2次就可以,大大提高了效率。

所以,计算结构体大小时考虑内存对齐是典型的“以空间换时间”的案例,用少量的内存空间浪费换取CPU寻址效率的提升。

三、结构体大小计算示例

来看一个具体的题目:

//假设是32bit系统
#include <stdio.h>
struct A{int i;char j;char * ptr;long Array[100];char b[2];char * c;
};
int main()
{printf("%d\n", sizeof(struct A));return 0;
}

在32位系统中,各成员的对齐数(自身大小)如下:

  • int i:4字节(对齐数4)
  • char j:1字节(对齐数1)
  • char *ptr:4字节(指针在32位系统中占4字节,对齐数4)
  • long Array[100]:每个long占4字节(对齐数4),数组整体占4×100=400字节
  • char b[2]:2字节(对齐数1,数组整体占2字节)
  • char *c:4字节(对齐数4)

分步计算过程:

  1. int i
    从地址0开始存储,占用4字节(地址0~3)。

  2. char j
    对齐数为1,可紧跟在i之后,从地址4开始,占用1字节(地址4)。

  3. char *ptr
    对齐数为4,需从4的整数倍地址开始。当前已用地址到4,下一个4的整数倍地址是8,因此从地址8开始存储,占用4字节(地址8~11)。
    注意:地址5~7为填充空间(3字节,因j只占1字节,需补齐到4的整数倍才能存放ptr)。

  4. long Array[100]
    对齐数为4,当前已用地址到11,下一个4的整数倍地址是12,从地址12开始存储,占用400字节(地址12~411)。

  5. char b[2]
    对齐数为1,紧跟Array之后,从地址412开始,占用2字节(地址412~413)。

  6. char *c
    对齐数为4,需从4的整数倍地址开始。当前已用地址到413,下一个4的整数倍地址是416,从地址416开始存储,占用4字节(地址416~419)。
    注意:地址414~415为填充空间(2字节)。

总大小计算:

所有成员存储结束后,最后一个成员c占用到地址419,此时已用空间为420字节(0~419共420字节)。
由于结构体最大对齐数为4(所有成员的对齐数均不超过4),420是4的整数倍(420÷4=105),满足整体对齐要求。

因此,结构体struct A的大小为420字节

四、按需分配内存:取消内存对齐

在某些嵌入式产品中,内存大小极其有限,我们希望内核在分配内存单元时采用“按需分配”的原则,也就是取消内存对齐。这时候可以使用C语言标准的预处理指令#pragma pack(n),其中n的值可以是1、2、4、8等,用于进行字节对齐以及取消字节对齐。
image

例如:

#pragma pack(1)  // 取消字节对齐
struct studentinfo
{char name[10];int *p;short b;char c;int a;unsigned int age;
};
#pragma pack()  // 恢复字节对齐

在取消字节对齐后,计算结构体大小就是各成员大小的简单相加,比如上述结构体计算得到的大小是29字节,相比有内存对齐时的大小,节省了内存空间,不过这是以牺牲CPU寻址效率为代价的。

五、总结

内存对齐是C语言中一个重要的概念,它平衡了内存空间和CPU寻址效率。在大多数情况下,默认的内存对齐能够很好地提升程序性能。但在内存资源极度紧张的场景下,我们可以通过#pragma pack指令来取消内存对齐,实现“按需分配”内存。

http://www.wxhsa.cn/company.asp?id=6062

相关文章:

  • 该练习 DP 了!
  • 本周计划
  • PPT文件太大?一招「无损」压缩图片,秒变传输小能手!
  • U3D动作游戏开发读书笔记--2.3 3D游戏所需要的数学知识
  • 9月16模拟赛
  • C++ 单例 Meyers Singleton(迈耶斯单例)
  • EF Core 与 MySQL:查询优化详解
  • 短视频营销运营资深导师张伽赫,东莞绳木传媒创始人
  • 20250913
  • 文件的读取操作
  • 9.13日总结
  • 哇哇哇下雨了!——2025 . 9 . 16
  • 奇思妙想(胡思乱想)
  • AI Compass前沿速览:GPT-5-Codex 、宇树科技世界模型、InfiniteTalk美团数字人、ROMA多智能体框架、混元3D 3.0
  • C++中set与map的自定义排序方法详解
  • id
  • 【汇总】Qt常用模块头文件
  • Advanced Algorithm —— Hashing and Sketching
  • CF2136 Codeforces Round 1046 (Div. 2) 补题
  • 【IEEE出版、EI检索稳定】第四届云计算、大数据应用与软件工程国际学术会议(CBASE 2025)
  • 缺省源
  • 97. 交错字符串
  • MODint(自动取模)
  • BFD实验
  • 2025.9.16——卷1阅读程序1、2
  • 用Context Offloading解决AI Agent上下文污染,提升推理准确性
  • HCIP-BFD
  • MISC相关
  • VRRP实验
  • 在 Windows 10 上安装 FFmpeg 8.0