【C语言】—— 结构体内存对齐

一、存在内存对齐的原因

1、平台原因
不是所有硬件平台都能够访问任意地址上的任意数据的,某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
2、性能原因(主要原因)
数据结构(尤其是栈)应该尽可能地在自然边界上对齐。 原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。

这里我们举个例子说明一下
【C语言】—— 结构体内存对齐_第1张图片
注:内存对齐是以空间换时间的做法

二、内存对齐的规则

1、结构体的第一个变量必须放在结构体空间起始位置偏移量为0的地址处。
2、结构体的其余变量必须放在某个对齐数整数倍处。
3、这个对齐数是结构体变量的大小与默认对齐数的较小值。
4、默认对齐数:VS下的默认对齐数是:8
Linux gcc编译器下的默认对齐数是:4
5、结构体的总大小必须是所有结构体变量对齐数的最大值的整数倍。
6、 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有结构体变量对齐数中最大对齐数(含嵌套结构体的对齐数)的整数倍。

三、结构体大小的计算

下面我们来看几个练习,深入了解一下结构体内存对齐的规则

//练习1
struct S1
{
	char c1;
	int i;
	char c2;
};
//练习2
struct S2
{
	char c1;
	char c2;
	int i;
};

int main()
{
	printf("%d\n", sizeof(struct S1));//12
	printf("%d\n", sizeof(struct S2));//8

	return 0;
}

在计算结构体大小之前,先在这里介绍一个宏offsetof,用于计算结构体变量在结构体空间起始位置的偏移量,使用格式为

size_t offsetof( structName, memberName );

【C语言】—— 结构体内存对齐_第2张图片
再来看两个稍微复杂一点的练习

struct S3
{
	double d;//大小:8,默认对齐数:8 对齐数:8 所占空间:0-7
	char c;//大小:1 默认对齐数:8 对齐数:1 所占空间:8-8
	int i;//大小:4 默认对齐数:8 对齐数:4 所占空间:12-15
};//总空间大小:0-15 共16字节
//练习4-结构体嵌套问题
struct S4
{
	char c1;//大小:1 默认对齐数:8 对齐数:1 所占空间:0
	struct S3 s3;//大小:16 默认对齐数:8 对齐数:8 所占空间:8-23
	double d;//大小:8 默认对齐数:8 所占空间:24-31
};//总空间大小:0-31 共32个字节
int main()
{
	printf("%d\n", sizeof(struct S3));//16
	printf("%d\n", sizeof(struct S4));//32
	
	return 0;
}

四、修改默认对齐数

实现方法

其实很简单,只需要使用预处理命令#pragma pack(),将你想改的对齐数写在括号中即可,修改默认对齐数。

看看代码实现

//修改默认对齐数
#include 
#pragma pack(8)//设置默认对齐数为8
struct S1
{
	char c1;
	int i;
	char c2;
};
#pragma pack()//取消设置的默认对齐数,还原为默认
#pragma pack(1)//设置默认对齐数为1
struct S2
{
	char c1;
	int i;
	char c2;
};
#pragma pack()//取消设置的默认对齐数,还原为默认
int main()
{
	//输出的结果是什么?
	printf("%d\n", sizeof(struct S1));//12
	printf("%d\n", sizeof(struct S2));//6
	return 0;
}

你可能感兴趣的:(C语言学习,C语言,结构体,内存对齐)