首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >【C语言】结构体内存对齐:为什么你的结构体比想象中更大?

【C语言】结构体内存对齐:为什么你的结构体比想象中更大?

作者头像
苏兮
发布2026-01-13 17:22:48
发布2026-01-13 17:22:48
1570
举报

C语言学习

前言:

在上一篇博客《结构体详解:声明、使用与优化技巧》中,我们讨论了结构体的声明、使用……然而,在实际开发中,结构体的内存布局往往隐藏着更微妙的细节——比如为什么一个看似简单的结构体却占用了意料之外的内存空间?这背后正是内存对齐在起作用。 本文将深入剖析结构体内存对齐的规则,结合实例分析对齐对程序性能与空间的影响,并分享如何通过合理设计结构体来优化内存使用。


一、对齐规则

首先得掌握结构体的对齐规则:

  1. 结构体的第⼀个成员对齐到和结构体变量起始位置偏移量为0的地址处
  2. 其他成员的起始偏移量必须是对齐数的整数倍 对齐数 = 编译器默认的⼀个对齐数与该成员变量大小的较小值
    • VS 中默认的值为 8
    • Linux和 gcc 没有默认对齐数,对齐数就是成员自身的大小
  3. 结构体总大小为最大对齐数(结构体中每个成员变量都有⼀个对齐数,所有对齐数中最大的)的整数倍。
  4. 如果嵌套了结构体的情况,嵌套的结构体成员对齐到自己的成员中最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体中成员的对齐数)的整数倍。 知道了对齐规则,怎么来实战练习一下: 练习1:
代码语言:javascript
复制
struct S1
{
	char c1;
	int i;  
	char c2;
};
int main()
{
	printf("%d\n", sizeof(struct S1));
	return 0;
}

解析:(注意每个成员都有对齐数

练习2:

代码语言:javascript
复制
struct S2
{
	char c1;
	char c2;
	int i;
};
int main()
{
	printf("%d\n", sizeof(struct S2));
	return 0;
}

解析:

在这里插入图片描述
在这里插入图片描述

练习3:

代码语言:javascript
复制
struct S3
{
	double d;
	char c;  
	int i;   

};
int main()
{
	printf("%d\n", sizeof(struct S3));
	return 0;
}

解析:

在这里插入图片描述
在这里插入图片描述

练习4-结构体嵌套问题:

代码语言:javascript
复制
struct S3
{
	double d;
	char c;  
	int i;  
};
struct S4
{
	char c1;     
	struct S3 s3;
	double d;    
};
int main()
{
	printf("%d\n", sizeof(struct S4));
	return 0;
}

解析:

在这里插入图片描述
在这里插入图片描述

对于结构体对齐规则就到这,那为什么进行内存对齐?也就是为什么存在内存对齐呢?

二、为什么存在内存对齐

大部分的参考资料都是这样说的:

  1. 平台原因 (移植原因): 不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定 类型的数据,否则抛出硬件异常。
  2. 性能原因: 数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要 作两次内存访问;而对齐的内存访问仅需要⼀次访问。假设⼀个处理器总是从内存中取8个字节,则地 址必须是8的倍数。如果我们能保证将所有的double类型的数据的地址都对齐成8的倍数,那么就可以 ⽤⼀个内存操作来读或者写值了。否则,我们可能需要执行两次内存访问,因为对象可能被分放在两 个8字节内存块中。

总体来说:结构体的内存对齐是拿空间来换取时间的做法。 那在设计结构体的时候,我们既要满足对齐,又要节省空间,如何做到:

让占用空间小的成员尽量集中在一起

代码语言:javascript
复制
//例如:练习1与练习2
struct S1
{
	char c1;
	int i;
	char c2;
};
struct S2
{
	char c1;
	char c2;
	int i;
}

S1 和 S2 类型的成员⼀模⼀样,但是 S1 和 S2 所占空间的大小(S1为12、S2为8)有了⼀些区别。

三、修改默认对齐数

#pragma 这个预处理指令,可以改变编译器的默认对齐数。 咱们可以来试一试:

代码语言:javascript
复制
#include <stdio.h>
#pragma pack(1)//设置默认对⻬数为1
struct S
{
	char c1;
	int i;
	char c2;
};
int main()
{
	//输出的结果是什么?
	printf("%d\n", sizeof(struct S));
	return 0;
}

这样的话,大小就为6了; 调试:

在这里插入图片描述
在这里插入图片描述

咱们也可以将默认对齐数修改回来:

代码语言:javascript
复制
#include <stdio.h>
#pragma pack(1)//设置默认对⻬数为1
struct S
{
	char c1;
	int i;
	char c2;
};
#pragma pack()//取消设置的对1数,还原为默认
int main()
{
	//输出的结果是什么?
	printf("%d\n", sizeof(struct S));
	return 0;
}

总结

对齐是硬件友好的契约,更是跨平台的护城河。 下次当sizeof结果出乎意料时,不妨画个内存布局图——真相就在偏移量的数字里!

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-08-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • C语言学习
  • 前言:
  • 一、对齐规则
  • 二、为什么存在内存对齐
  • 三、修改默认对齐数
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档