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

一、结构体内存对齐规则


1.第一个成员在与结构体变量偏移量为0的地址处
2.其他成员变量要对齐到某个数字(对齐数)的整数倍地址(偏移量) gcc编译器没有默认对齐数 成员大小就是对齐数
对齐数=编译器默认的一个对齐数(VS默认为8)与该成员大小之间的一个较小值
3.结构体的总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍
4.如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处, 结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍


见下列代码:

struct S1//结构体变量
{
    
    
	char c1;//1 c1 第一个成员
	int a;//4   4<8 对齐数为4  此时4为该结构体的最大对齐数
	char c2;//1 对齐数为1
};
struct S2
{
    
    
	char c1;//1
	char c2;//1
	int a;//4
};
#include<stdio.h>
int main()
{
    
    
	struct S1 s1 = {
    
     0 };
	printf("%d\n", sizeof(s1));
	struct S2 s2 = {
    
     0 };
	printf("%d\n", sizeof(s2));
	return 0;
}

运行结果:

12
8

解释(以S1为例):

  • 1.第一个成员在与结构体变量偏移量为0的地址处。代码中的c1就是第一个成员,而c1占1个字节,所以c1存储在下图蓝色部分

  • 2.其他成员变量要对齐到某个数字(对齐数)的整数倍地址(偏移量) gcc编译器没有默认对齐数 成员大小就是对齐数。
    对齐数=编译器默认的一个对齐数(VS默认为8)与该成员大小之间的一个较小值 。
    我用的是VS,所以默认对齐数为8。第二个成员c2的大小为4,4<8,所以c2的对齐数是4,所以c2从偏移量为4的倍数的数开始存储,因为偏移量4后还没存储任何数,所以c2从偏移量为4处开始存储,又c2占4个字节,所以c2存储在下图绿色部分

  • 同理,c3存储在下图橙色部分

  • 3.结构体的总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。将c1 c2 c3都按规则存储完后,应共占1+4+1=6个字节,但结果是12。因为按照前三条对齐规则,白色部分必须是空出来的,而按照本条对齐规则,因为c2的大小最大,为4,所以S1的最大对齐数为4,而按照前三条对齐规则存储完后,加上空白部分为9,最接近4的倍数12,所以应再加上三个空白部分,即黄色部分

  • 在这里插入图片描述

  • 综上所述,结构体S1的大小为12

  • 通过运算结果我们发现,只是将c1和a的位置换了一下,结构体大小就从12变成了8,所以我们应让空间小的成员尽量集中在一起


  • 4.如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处, 结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍
    见代码:
struct S3
{
    
    
	double d;//8
	char c;//1
	int i;//4
};
struct S4
{
    
    
	char c1;//1
	struct S3 s3;//16 最大对齐数为8 从偏移量为8的时候开始
	double d;//8
};
#include<stdio.h>
int main()
{
    
    
	struct S3 s3 = {
    
     0 };
	printf("%d\n", sizeof(s3));
	struct S4 s4 = {
    
     0 };
	printf("%d\n", sizeof(s4));
	return 0;
}

运算结果:

16
32

解释:

  • 按照对齐规则可求出S3的大小为16
  • 计算S4大小时16>8,所以对齐数为8
  • 可同理计算出S4的大小为32

二.为什么存在内存对齐

  • 1.平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取得某些特定类型的数据,否则抛出硬件异常
    2.性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问只需要一次访问
    总体来说,结构体的内存对齐是拿空间换取时间的做法
  • 那在设计结构体时既要满足对齐又要节省空间,如何做到?
    1.应让空间小的成员尽量集中在一起
    2.修改默认对齐数 #pragma 一般为2的次方数

猜你喜欢

转载自blog.csdn.net/m0_74102736/article/details/130451808