欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

结构体内存对齐

程序员文章站 2022-07-12 16:57:29
...
#include <stdio.h>
#include <iostream>

typedef struct
{
	char a;		//偏移地址0
	int b;		//偏移地址4
	char c[3];  //偏移地址8
	double d;	//偏移地址16
}S;

int main(int argc, char *argv[])
{
	S s1;
	s1.a = 'a';
	s1.b = 0x020304;
	s1.d = -125;
	for (int i = 0; i < 3; i++)
		s1.c[i] = 'A' + i;

	unsigned int s1_addr = (unsigned int)&s1;
	unsigned int a_addr = (unsigned int)&s1.a;
	unsigned int b_addr = (unsigned int)&s1.b;
	unsigned int c_addr = (unsigned int)&s1.c;
	unsigned int d_addr = (unsigned int)&s1.d;

	//std::cout << s1.a << s1.b << s1.c << std::endl;  
	printf("sizeof(S) = %d\n\n", sizeof(S));
	printf("s1.a = %u\n", s1.a);
	printf("s1.b = %d\n", s1.b);
	printf("s1.c = %s\n", s1.c);
	printf("s1.d = %f\n\n", s1.d);

	printf("s1_addr = %lu = 0x%x\n", s1_addr, s1_addr);
	printf("a_addr  = %lu = 0x%x\n", a_addr, a_addr);
	printf("b_addr  = %lu = 0x%x\n", b_addr, b_addr);
	printf("c_addr  = %lu = 0x%x\n", c_addr, c_addr);
	printf("d_addr  = %lu = 0x%x\n\n", d_addr, d_addr);

	printf("s1_addr %% sizeof(maxType) = %lu %% %d = %d\n", &s1, sizeof(double), s1_addr % sizeof(double));

	printf("a_addr  %% sizeof(char)    = %lu %% %d = %d\n", a_addr, sizeof(char), a_addr % sizeof(char));
	printf("b_addr  %% sizeof(int)     = %lu %% %d = %d\n", b_addr, sizeof(int), b_addr % sizeof(int));
	printf("c_addr  %% sizeof(char[])  = %lu %% %d = %d\n", c_addr, sizeof(char), c_addr % sizeof(char));
	printf("d_addr  %% sizeof(double)  = %lu %% %d = %d\n\n", d_addr, sizeof(double), d_addr % sizeof(double));
	system("pause");
	return 0;
}

一、测试环境:

    Win7(64-bit)

    VS2015(32-bit)

二、运行结果

(1)结构体首地址可以被8整除

结构体内存对齐

结构体内存对齐

(2)结构体首地址可以被4整除

结构体内存对齐

结构体内存对齐

三、分析

结构体所占用的内存与其成员在结构体中的声明顺序有关,其成员的内存对齐规则如下:

1.结构体每个成员相对于结构体首地址的偏移量(offset)都是(这个)成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internaladding);

2.结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节(trailingpadding)。

3.字节对齐取决于编译器。每个成员分别按自己的对齐字节数(char=1,int=4,double=8)PPB指定的对齐字节数,由#pragam pack宏定义,32位机默认为4两个字节数最小的那个对齐,这样可以最小化长度。

4.对于结构体成员属性中包含结构体变量的复合型结构体再确定最宽基本类型成员时,应当包括复合类型成员的子成员。但在确定复合类型成员的偏移位置时则是将复合类型作为整体看待。

5.总结出一个公式:结构体的大小等于最后一个成员的偏移量加上其大小再加上末尾的填充字节数目,即:

sizeof( struct ) = offsetof( last item ) + sizeof( last item ) +sizeof( trailing padding )

四、相关参考

(1)结构体打包原理-GitHub

(2)数据对齐详解

(3)结构体内存空间分配原理

(4)阿里面试题

(5)内存对齐 CPU模型

(6)32位及64位系统上基本数据类型使用内存空间大小