简析结构体存储分配

简析结构体的存储分配

结构与数组类似,但是两者之间存在着很大的差别。数组是通过下标进行访问,而结构是通过其成员的名字进行访问的。其次结构体内部成员更加灵活,那么结构体在内存中的存储是怎么分配的?
来看下面代码:
#include <stdio.h>
struct S1
{
	int a;
	char c;
};
struct S2
{
	char c;
	int a;
};

int main()
{
	 printf("%d\n", sizeof(struct S1));
	 printf("%d\n", sizeof(struct S2));
	 system("pause");
	 return 0;
}


程序运行结果为:


关于这段代码中的结构体内存分配,看下图:


我们可以通过 宏offsetof来验证一下,结构体成员在内存中的分配是否如上图所示.
#define offsetof(struct_t,member) ((size_t)(char  *)&((struct_t *)0)->member) 
offsetof返回的是结构体成员在结构体内存中的偏移量。
其函数原型在MSDN中为下:

看代码如下:
#include <stdio.h>
#include<stddef.h>
struct S1 
{
	int a;
	char c;
};
struct S2
{
	char c;
	int a;
};

int main()
{
	 printf("%d  ", offsetof(struct S1, a));
	 printf("%d\n", offsetof(struct S1, c));
	 printf("%d  ", offsetof(struct S2, a));
	 printf("%d\n", offsetof(struct S2, c));
	 system("pause");
	 return 0;
}
程序运行结果为:


这个即说明:
1. 结构体的第一个成员在与结构体变量偏移量为0的地址处。
2. 结构体在内存中存储时会发生对齐,其对齐规则为:其他成员变量要对齐到对齐数的整数倍的地址处。
//对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。(VS中默认对齐数的值为8,linux中的默认值为4)

再看下面代码:
#include <stdio.h>
struct S
{
	double a;
	char c;
	float d;
	short e[2];
};
int main()
{
	printf("%d\n", sizeof(struct S));
	system("pause");
	return 0;
}
此程序运行结果为多少呢?  
根据上面的规则来分析,a占据前8个字节,c占据第9个字节,d根据对齐占据第13~16这4个字节,e[2]占据17~20这四个字节。那么结构体总大小应为20。然而结构却不是如此。


此段代码运行的结果为:24。也就是说在存储完e[2]后,结构体又多占据了四个字节的空间。这是什么情况?
因为: 结构体总大小为最大对齐数(每个成员变量除了第一个成员都有一个对齐数)的整数倍。
而上面代码中结构体最大对齐数为8,而最后算的为20,不是8的倍数,所以再多开辟4个字节的空间,即24个字节的空间。
了解了这个规则后,来看这个代码:
#include <stdio.h>
struct S
{
	int a;
	char c;
	float d;
	short e;
};
int main()
{
	printf("%d\n", sizeof(struct S));
	system("pause");
	return 0;
}
可以很容易的分析有:a占据前四个字节,c占据第5个字节,d占据第9~12个字节,e占据第13~14个字节,又因为此结构体最大对齐数为4,所以结构体大小要为四的倍数,即要再开辟两个自己的空间,因此,此结构体空间大小为:16。
程序运行结果:


那么如果结构体嵌套了,其内存又是如何分配的?
看代码:
#include <stdio.h>
struct S1
{
	char c;
	int a;
};
struct S2
{
	char d;
	struct S1 s1;
	int e;
	double f;
	short h[2];
};

int main()
{
	printf("%d\n", sizeof(struct S1));
	printf("%d\n", sizeof(struct S2));
	system("pause");
	return 0;
}
此段代码运行结果如下:


分析,其在内存中的存储如下:


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

如果结构体中包含了指针的话,其内存分配如下:
#include <stdio.h>
struct S1
{
	char c;
	int a;
	int* p;
	char* q;
};

int main()
{
	printf("%d\n", sizeof(struct S1));
	system("pause");
	return 0;
}
程序运行结果为:


分析,c占据第一个字节,a占据第5~8个字节,而无论是int指针还是char指针都占据了4个字节。
所以: 结构体中包含指针,无论指针是何种类型,其占据内存均为4个字节(64位机器上8个字节)。

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


以上即为对结构体存储分配的简单解析,如有不足,还请大家指出!
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值