结构体是一种自定义类型,结构体变量是怎么在内存中的存储的?

结构体在存储数据时,需遵循对齐规则。也因为对齐规则,使得结构体存储数据时,与平时所想存在很大差异,举几个例子

struct x1
{
	char c1;
	int i;
	char c2;
};
struct x2
{
	char c1;
	char c2;
	int i;
};
int main()
{
	//text();
	struct x1 a;
	struct x2 b;
	printf("%d %d", sizeof(a), sizeof(b));
	return 0;
}

ios 数组存储结构体类型 结构体数组的存储_ios 数组存储结构体类型

是不是有些奇怪

成员变量相同的结构体,只因成员变量的顺序不同便导致了整个结构体变量大小的不同

想要理解结构体的大小,便要从结构体数据在内存中是如何存储的下手

先从结构体的内存对齐规则开始

对齐规则

  • 1. 第一个成员在与结构体变量偏移量为0的地址处。
  • 2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
  • 3. 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
  • 4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整 体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

 想要理解对齐规则,不妨先理解一下这两个名词

  • 偏移量:指把存储单元的实际地址与其所在段的段地址之间的距离称之为段内偏移
  •               简单来说,就是相对位置
  • 对齐数:对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。
  •               VS中默认的值为8

单理解规则难免会有些困难,不妨与代码结合

//创建一个结构体类型,并重命名为x1
typedef struct x1
{
	char c1;
	int i;
	char c2;
}x1;
//创建一个x1类型的变量a
x1 a = {0};

以结构体x1为例

结构体a先像内存申请了一块空间

假设此为变量的首地址

ios 数组存储结构体类型 结构体数组的存储_c语言_02

 1. 第一个成员在与结构体变量偏移量为0的地址处。

由规则一可知,第一个成员放置于结构体变量偏移量为0的地址处

就像上文说的,偏移量起始是一种相对位置,相对于首地址的位置。

按照与首地址的位置关系,以将偏移量在图中标识出

char类型占1个字节,即

ios 数组存储结构体类型 结构体数组的存储_蓝桥杯_03

 2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。

先大致讲一下规则,每个成员都有字节的对齐数

对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。(VS中默认的值为8)

在vs的环境下,

以int i为例子

int i  的大小为 4 , 4 < 8 (默认对齐数)   故int i  的对齐数为 4。

即 int i  必需要对齐到 4 的正数倍处。

偏移量为4的位置,满足

ios 数组存储结构体类型 结构体数组的存储_c语言_04

 c2同理

ios 数组存储结构体类型 结构体数组的存储_ios 数组存储结构体类型_05

 3. 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。

何为最大对齐数呢?

结构体的三个成员各自都存在一个对齐数

成员

对齐数

c1

1

i

4

c2

1

可以发现最大的对齐数为 4 

即结构体的大小应该为最大对齐数的整数倍,目前结构体已经占用了9个字节

应该为4的整数倍,故结构体的大小应该为12

4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整 体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

嵌套的结构体作为一个成员时,他的最大对齐数便是嵌套的结构体中成员的最大的对齐数

如果将上文的结构体嵌套如结构体中,上文结构体的最大对齐数便是4.