结构体内存对齐

image

结构体内存对齐

为什么存在内存对齐

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

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

2.性能原因

数据结构(尤其是栈)应该尽可能的在自然边界上对齐,为了访问未对齐的内存,CPU需要访问内存2次;访问对齐后的内存,CPU只需要访问内存1次。

在Windows的VS中默认对齐值为8

Linux中(GCC编译器)默认对齐值为4

在内存中我们一般读取数据不是按内存来读取,一般都是按内存块来读取。

未对齐的情况下,当需要访问int类型的数据时,需要CPU访问2次内存块(内存块1和内存块2)

对齐的情况下,当访问int类型的数据时,只需要CPU访问1次内存块(内存块2)即可

是一种空间换时间的做法

结构体内存对齐规则

  • 第一个成员在结构体变量偏移量为0的地址
  • 有效对齐值为Min(编译器默认对齐值,结构体中成员数据类型中占用内存最大值)
  • 其他成员要对齐到**Min(有效对齐值,该成员数据类型的内存大小)**的整数倍
  • ⚠结构体总大小为有效对齐值的整数倍
  • 如果嵌套结构体,有效对齐值为Min(编译器默认对齐值,Max(嵌套结构体中成员数据类型中占用内存最大值,结构体中成员一数据类型占用内存、结构体中成员二数据类型占用内存……结构体中成员N数据类型占用内存))
  • 如果嵌套共同体,有效对齐值为Min(编译器默认对齐值,Max( ​Max(共同体内成员一、共同体内成员二……共同体内成员N)结构体中成员一数据类型占用内存​**、结构体中成员二数据类型占用内存……结构体中成员N数据类型占用内存))**
  • 共用体所占内存大小:Max(共同体内成员一、共同体内成员二……共同体内成员N***)***

举例

#pramga pack(n)​告诉编译器字节对齐方式为n字节对齐

#pramga pack(8)
struct s1{
	char a;
	int b;
	char c;
};

结构体中最大的成员数据类型占用4字节,有效对齐值为Min(8,4)=4;char为第一个成员,应在结构体偏移量为0的地址,占用1字节;int占用4字节,要对齐在Min(8,4)=4的整数倍位置,即4的位置(4,5,6,7);char占用1字节,要对齐在Min(8,1)=1的整数倍位置,即8位置;因为结构体总大小为有效对齐值的整数倍,所以结构体的大小应为12(0~11)

#pramga pack(8)
struct s1{
	char a;
	int b;
	char c;
};
struct s2{
	char a1;
	struct s1 S1;		//嵌套结构体
	double d;
};

结构体s1中最大数据类型结构为int占用4字节,结构体s2的有效对齐值为Min(8,Max(4,1,8))=8;char为第一个成员,应在结构体偏移量为0的地址,占用1字节;嵌套结构体s1(占用12字节)要对齐在Min(8,4)=4的整数倍,即4(4-15);double占用8字节,要对齐在Min(8,8)的整数倍位置,即16(16-23);因为结构体总大小为有效对齐值的整数倍;此时结构体内存大小为24,满足要求。

#pramga pack(4)
struct s1{
	char a;
	int b;
	union w{
		int c;
		double d;
	}w;
	short e;
};

共同体w中最大数据类型占用内存为Max(4,8)=8;结构体s1的有效对齐值为Min(4,Max(8,1,4,2))= 4;char为第一个成员,应在结构体偏移量为0的地址,占用1字节;int占用4字节,要对齐在Min(4,4)=4的整数倍位置,即4的位置(4,5,6,7);共同体w占Max(4,8)=8字节,要对齐在Min(4,12)=4的整数倍位置,即8的位置(8-15);short占2字节,要对齐在Min(4,2)=2的整数倍为止,即16(16-17);因为**结构体总大小为有效对齐值的整数倍**;所以结构体s1的大小需要补位到4的整数倍,即20字节。

posted @ 2023-07-10 09:58  清光照归途  阅读(50)  评论(0编辑  收藏  举报