您现在的位置是:首页 >技术教程 >嵌入式 C/C++ 开发之压榨程序大小——结构体优化:用好了能省 50% 的空间网站首页技术教程
嵌入式 C/C++ 开发之压榨程序大小——结构体优化:用好了能省 50% 的空间
嵌入式 C/C++ 开发之压榨程序大小——结构体优化:用好了能省 50% 的空间
在 C 和 C++ 编程中,结构体(struct)的内存布局对程序的性能和内存使用有着重要的影响,尤其是在嵌入式开发中,RAM 也就那么 16K、8K 甚至 4K,寸土寸金,容不得一丝浪费。本文将详细介绍如何通过理解对齐要求、填充、结构体重新排序等技术来优化结构体的内存布局,缩小程序占用空间,从而提高程序的效率和性能。
1. 对齐要求
编译器在内存中布局基本数据类型时受到对齐要求的约束,以加快内存访问速度。这些约束导致了相同的布局,包括 Intel、ARM 和 RISC-V 等架构。除了 char 类型外,其他基本的 C 语言数据类型都有对齐要求。例如,2 字节的 short 必须从偶数地址开始,4 字节的 int 或 float 必须从能被 4 整除的地址开始,8 字节的 long 或 double 必须从能被 8 整除的地址开始。这种自我对齐的特性使得内存访问更快。
但是,这也导致了部分内存空间的额外占用——填充。
2. 填充
填充是指编译器在结构体成员之间或结构体末尾添加的额外字节,以满足对齐要求。例如,考虑以下结构体(64 位系统下):
struct foo1 {
char *p; /* 8 字节 */
char c; /* 1 字节 */
long x; /* 8 字节 */
};
在这个结构体中,char 类型的 c 成员后面需要添加 7 字节的填充,以确保 long 类型的 x 成员从 8 字节对齐的地址开始:
struct foo1 {
char *p; /* 8 字节 */
char c; /* 1 字节 */
//char pad[7]; /* 7 字节填充 */
long x; /* 8 字节 */
};
这种填充虽然可以确保数据的快速访问,但也导致内存的浪费。
3. 结构体对齐和填充
结构体的对齐通常是按照其成员最宽的长度进行对齐。例如,如果一个结构体包含一个 long 类型的成员,那么整个结构体将具有 8 字节对齐。这意味着结构体的地址与其第一个成员的地址相同,没有前面的填充。然而,结构体的末尾可能会有尾随填充,以确保下一个结构体实例从正确的对齐地址开始。
4. 位字段
位字段允许你在结构体中声明小于字符宽度的字段,小到 1 位。例如:
struct foobits {
short s;
char c;
int flip:1;
int nybble:4;
int septet:7;
};
位字段的布局受到 C 标准的限制,它们不能跨越存储单位边界。C99 保证位字段将尽可能紧密地打包,但 C++14 放宽了这一限制,允许位字段跨越多个分配单元。
5. 结构体重新排序
由上述对其及填充的规则学习得知,我们可以通过重新排序结构体成员,来减少填充并优化内存布局。
通常,按对齐要求从大到小的顺序排列成员可以减少填充。
例如,将指针对齐的成员放在前面,然后是 4 字节的 int,接着是 2 字节的 short,最后是 char 类型的成员。
这种方法可以显著减少结构体的总体大小,从而提高内存使用效率。
6. 结构体优化的实际应用
考虑一个复杂的结构体,包含多种不同类型的数据成员:
struct complex {
char c1;
int i1;
short s1;
long l1;
char c2;
};
在这个结构体中,c1 和 c2 之间以及 l1 末尾会有填充。通过重新排序成员,我们可以减少填充:
struct complex {
long l1;
int i1;
short s1;
char c1;
char c2;
};
这种重新排序后的结构体只在 l1 和 i1 之间有 4 字节的填充,因为 i1 需要 4 字节对齐。c1 和 c2 之间没有填充,因为 c1 已经在 i1 的填充内。
优化对比,文末可获取 demo:

结论
理解并应用结构体优化技术对于提高 C 和 C++ 程序的性能和内存效率至关重要。
通过对齐要求、填充和结构体重新排序的理解,开发者可以设计出更高效、更紧凑的数据结构,从而在保持代码可读性的同时,提高程序的整体性能。
记住,优化结构体不仅仅是减少内存占用,它还可以提高程序的运行速度,特别是在处理大量数据或在内存受限的环境中。
文章配套 demo 源码仓库:结构体优化对比demo
也可扫码关注博主同名公众号"不解之榬",私信获取






U8W/U8W-Mini使用与常见问题解决
QT多线程的5种用法,通过使用线程解决UI主界面的耗时操作代码,防止界面卡死。...
stm32使用HAL库配置串口中断收发数据(保姆级教程)
分享几个国内免费的ChatGPT镜像网址(亲测有效)
Allegro16.6差分等长设置及走线总结