详解结构体内存对齐

Posted 流浪孤儿

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了详解结构体内存对齐相关的知识,希望对你有一定的参考价值。

目录

结构体内存对齐的概念

 结构体内存对齐的规则

 结构体大小的计算

第一步:确定每个成员变量的对齐数

 第二步:定位

 第三步:确定该结构体的大小

结构体为什么要内存对齐

VS下修改默认对齐数 

调整结构体大小

offsetof函数的使用


结构体内存对齐的概念

 定义一个结构体变量

struct S

	char c1;//1
	int i;//4
	char c2;//1
;


int main()

	printf("%d\\n", sizeof(struct S));

	return 0;

请问sizeof(struct S)是多大呢?有小伙伴会说无非就是把内部成员各自的大小加起来:1+4+1=6,因此答案就是6,可惜答案不是这个,而是12。

为啥相差这么大呢?因为结构体内的成员之间在内存中的位置并不是紧挨在一起的。

 即不是这样的:

 而是这样的:

 一个格子代表一个字节的大小,从图中也看不出12是哪里来的,大家细细的往下看

 这些成员进行了内存对齐,即按照某种规则将这些成员在内存中的位置进行了调整,这种规则称之为结构体内存对齐。内存对齐后其外在表现就是struct S这个结构体类型的大小就会发生改变,也就是说结构体大小遵循结构体内存对齐规则

 结构体内存对齐的规则

1.第一个成员在与结构体变量偏移量为0的地址处。
2.其他成员变量要对齐到自身对齐数的整数倍的地址处
        每个成员的对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。
        VS中默认的值为8(这个值可以进行修改)
        linux没有默认值,直接以该成员大小为对齐数
3.结构体总大小为最大对齐数(从每个成员变量的对齐数中挑选)的整数倍。
4.如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

如果大家看的不是很懂不用担心,接下来带着大家计算结构体大小 

 结构体大小的计算

 VS编译器下,默认对齐数是8

第一步:确定每个成员变量的对齐数

 

 第二步:定位

 定位:将每个成员变量在内存中的位置确定好

 

 第三步:确定该结构体的大小

 通过上图发现内存空间已经使用了9个格子即9个字节,那么结构体大小就是9了吗?其实还不是,根据结构体内存规则:结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。

对齐数有1,4,1,最大对齐数自然就是4了,那么12比9大,而且是最大对齐数4的整数倍,因此该结构体大小就是12,。

有小伙伴是否有疑问比如16,20也符合比9大,且是最大对齐数4的整数倍,那么为什么选择12呢?因为要尽可能的节省空间的使用啊!于是小伙伴又会问:节省空间的使用为什么还要内存对齐呢?不使用内存对齐的时候该结构体大小是6啊! 接下来帮助大家解释为什么存在内存对齐

结构体为什么要内存对齐

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

 

VS下修改默认对齐数 

 #pragma pack(num)

//num为具体的数,将默认对齐数设置为num大小

#include<stdio.h>

#pragma pack(2)  //一般设置为2的次方
struct S
			
	char c1;				
	int i;					
	char c2;				
;

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





 

调整结构体大小

 

 这里只是调整了结构体成员变量定义的顺序就导致了结构体大小的变化,

如果结构体成员的顺序设计得合理的话,比如将占用空间小的成员尽量集中在一起是可以避免不必要的内存消耗

 offsetof函数的使用

 头文件<stddef.h>

函数原型:size_t offsetof(type, member);

功能:返回指定成员从一开始的字节数偏移量

#include<stdio.h>
#include<stddef.h>
#pragma pack(2)
struct S1		
	char c1;
	char c2;
	int i;					
				
;

struct S2 
	char c1;
	int i;
	char c2;
;

int main()
	printf("struct S1 %d\\n", sizeof(struct S1));
	printf("c1 %d\\n", offsetof(struct S1, c1));
	printf("c2 %d\\n", offsetof(struct S1, c2));
	printf(" i %d\\n", offsetof(struct S1, i));

	printf("struct S2 %d\\n", sizeof(struct S2));
	printf("c1 %d\\n", offsetof(struct S2, c1));
	printf(" i %d\\n", offsetof(struct S2, i));
	printf("c2 %d\\n", offsetof(struct S2, c2));

	return 0;

执行结果:

以上是关于详解结构体内存对齐的主要内容,如果未能解决你的问题,请参考以下文章

内存字节对齐

详解结构体内存对齐

详解结构体内存对齐

[.NET] 结构体布局详解与结构体内存对齐具体方式

[.NET] 结构体布局详解与结构体内存对齐具体方式

3.c语音结构体成员内存对齐详解