结构体内存对齐——结构体内存大小的计算

文章讨论了C/C++中结构体内存对齐的规则,解释了为何sizeof(structs)不等于成员变量大小之和,介绍了编译器如何按照对齐规则调整结构体的内存布局,以及内存对齐对于平台兼容性和性能优化的重要性。

结构体类型大小的计算

我们可以使用sizeof计算变量,例如可以用sizeof(int)计算整形的大小为四个字节。

我们知道一个int类型的变量大小为四个字节,一个char类型的变量大小为一个字节。

那么,如果我们创建一个包含int a,char b类型的结构体类型struct s,此时struct s所占的内存是多少呢?按照我们的正常思维,我们会把int类型和char类型的大小直接相加,即struct s所占内存是五个字节,然而事实真的如此吗?我们再VS上进行验证。

#include<stdio.h>
int main()
{
	struct s
	{
		int a;
		char b;
	};
	printf("%d", sizeof(struct s));
	return 0;
}

运行结果如下:

奇怪的是,运行结果不为5,而为8,为什么呢? 

原来,结构体在内存中的存储并不是简单的连续存储,而是遵从着一定的规则进行存储。

结构体的对齐规则

结构体的对齐规则如下:

1. 第一个成员在与结构体变量偏移量为0的地址处。

2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。

对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。(VS中默认的值为8)

3. 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。

4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整

体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
 

例一、我们以结构体类型struct s1为例:

struct S1
{
char c1;
int i;
char c2;
};

c1大小为1个字节,作为第一个成员存储在偏与结构体变量移量为0的地址(占用0)

i大小为4个字节,对齐数为4,由于要对齐到4的整数倍的地址处,最近的即为偏移量为4的地址(占用4,5,6,7)

c2大小为1个字节,对齐数为1,同i对齐到1的整数倍的地址,最近的即为偏移量为8的地址(占用8)

目前结构体大小为九个字节,由于结构体总大小为最大对齐数的整数倍,即为4的整数倍,9个字节不足,至少要12个字节

综上所述,s1类型大小为12个字节

例二、我们再以嵌套结构体的情况为例,即以结构体类型struct s3为例:


struct S2
{
double d;
char c;
int i;
};
struct S3
{
char c1;
struct S2 s2;
double d;
};

c1大小为8个字节,作为第一个成员存储在偏与结构体变量移量为0的地址(占用0)

struct s2的最大对齐数为8,由于嵌套的结构体对齐到自己的最大对齐数的整数倍处,所以struct s2对齐到偏移量为8的地址(占用8~23)(易得s2占用16个字节)

d大小为8个字节,对齐数为8,对齐至偏移量为24的地址处(占用24~31)

目前结构体大小为32个字节,最大对齐数为8,,结构体总大小为最大对齐数的整数倍,符合要求

综上所述,s3类型大小为32个字节

采用内存对齐的原因

1. 平台原因(移植原因):

不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。

2. 性能原因:
数据结构(尤其是栈)应该尽可能地在自然边界上对齐。
原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。

总体来说,结构体的内存对齐是拿空间来换取时间的做法。
 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值