结构体内存对齐

结构体内存对齐

先看两段代码,两段代码仅顺序不同,其结果输出就出现了不同。

struct S
{
	char c1;//1 8 1
	int i;//4 8 4
	char c2;//1 8 1
};

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

int main()
{
	struct S s = { 0 };
	struct S2 s2 = { 0 };
	printf("%d\n", sizeof(s));//12
	printf("%d\n", sizeof(s2));//8
	return 0;
}

接下来对其中的S进行单独分析:

struct S
{
	char c1;//1
	int i;//4
	char c2;//1
};

int main()
{
	struct S s = { 0 };
	printf("%p\n", &s);//002FFED8
	printf("%p\n", &(s.c1));//002FFED8
	printf("%p\n", &(s.i));//002FFEDC
	printf("%p\n", &(s.c2));//002FFEE0
	return 0;
}

结构体内存对齐的规则:
1.结构体的第一个成员永远都对齐到结构体的起始位置处。

2.从第二个成员开始,每个成员都对齐到某个对齐数的整数倍处。

对齐数:成员自身大小和默认对齐数的较小值
默认对齐数:VS-8 Linux-gcc-4

3.结构体的总大小是所有成员中最大对齐数的整数倍。
结构体内存对齐_第1张图片
是一种以空间换时间的做法。
结构体内存对齐_第2张图片
4.嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。


struct S3
{
    double d;//0-7
    char c;//8
    //9-11空余
    int i;//12-15
};

struct S4
{
    char c1;
    struct S3 s3;
    double d;
};

int main()
{
	printf("%d\n", sizeof(struct S3));//16
	printf("%d\n", sizeof(struct S4));//32
	return 0;
}

结构体内存对齐_第3张图片
为什么存在内存对齐:

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

1.头文件:#include
2.

int main()
{
	printf("%d\n", offsetof(struct S, c1));//0
	printf("%d\n", offsetof(struct S, i));//4
	printf("%d\n", offsetof(struct S, c2));//8
	return 0;
}

3.宏参数无类型
\为续行符(将一行拆成两行) 也可以看成转义字符
后面加什么就转义什么
直接敲回车–转义回车

#define my_offsetof(structName,memName) \
(int)&(((structName*)0)->memName)
int main()
{
	printf("%d\n", my_offsetof(struct S, c1));//0
	printf("%d\n", my_offsetof(struct S, i));//4
	printf("%d\n", my_offsetof(struct S, c2));//8
	return 0;
}

结构体内存对齐_第4张图片

仅仅通过更换成员顺序,就可以改变所占字节大小,那在设计结构体的时候,我们既要满足对齐,又要节省空间,应该:
1.让占用空间小的成员尽量集中在一起。
2.修改默认对齐数

#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;
}

你可能感兴趣的:(结构体内存对齐)