结构体内存对齐后所占内存空间大小的计算

在项目开发中,很多时候其实会有用到sizeof一个结构体,具体什么时候用到呢。

比如说有这样一个结构体:

typedef struct tagOutCard
{
	short  UserId;			// 用户ID
	int    byCardCount;		// 出牌数目
	int    byCardData[20];	        // 扑克列表
}ST_OUT_CARD;

这是一个棋牌游戏中玩家出牌的数据包,需要将它赋值之后发送到服务器。

那么就会用到sizeof(ST_OUT_CARD)。

那到底这个ST_OUT_CARD是多大呢?

下面来说说怎么计算这个东西。

因为计算机为了加快读写数据的速度,编译器就实现了数据对齐的做法来为每一个结构体分配空间。这里就涉及到一个内存对齐的计算了。

下面用一个直观一点的结构体来示例计算:

typedef struct Data
{
	char a;        // 1  // 会扩展到4
	float b;       // 4
	double c;      // 8
	long long d;   // 8
	long double e; // 8
	long f;        // 4
	short g;       // 2 // 会扩展到4
	int h;         // 4
	bool i;        // 1
}ST_DATA;              // 最后结构体会是8的倍数

有这样一个包含了基本类型的Data结构体。

要想sizeof(ST_DATA)求得大小就要看内存分配了,下面就是计算这个结构体大小的过程:

按照自上向下的为结构体分配空间,并在它们之间作调整。首先为char分配一个空间,接着编译器为了实现数据的对齐,在分配float的时候会对之前所分配的空间进行一些调整,调整方式是按照原先分配的空间的大小和当前要分配的大小来决定将要分配的空间,因为float为4字节(可以自己sizeof(float)来看),所以编译器要求在float之前所分配的空间大小应该是当期要分配的空间的倍数,在这里也就是说在float前面分配的应该是4的倍数空间才行,所以原来的char被迫扩展到4个字节,然后才为float分配4个字节,这样这两个变量就占了8字节。由于double类型的数据占8个字节,是4的倍数,所以就直接相加。

现在就是a(4)+b(4)+c(8)+d(8)+e(8) +f(4)= 36。在int这个类型的时候这里也会是将short类型的内存字节扩展到4。

所以到最后的时候就是36+g(4)+h(4)+i(1) = 45。

以为这里就是对齐好了吗?sizeof出来就是45了吗?

其实还有一个就是编译器对结构体整体的一个倍数处理,已经为结构体分配好45个字节空间,那么接下来就是编译器要求整个结构体所分配的空间大小是结构体中占用空间最多的类型所占用空间大小的倍数。

如上面的例子,结构体中占用空间最多的就是8个字节的数据类型,那么就要求结构体总大小是这个类型的倍数,在这里也就是要求结构体所占用空间大小要是8 的倍数,因为45不是8的倍数,所以结构体被迫扩展自己的空间,以满足需要,所以就扩展到48个字节。

所以sizeof(ST_DATA)的结果是48,就是这样计算出来的。

文章导航