在讨论字节对齐之前我们先来看一个计算占用内存题目
#include <iostream.h>
#pragma pack(8)
struct example1
{
short a;
long b;
};
struct example2
{
char c;
example1 struct1;
short e;
};
#pragma pack()
int main(int argc, char* argv[])
{
example2 struct2;
cout << sizeof(example1) << endl;
cout << sizeof(example2) << endl;
cout << (unsigned int)(&struct2.struct1) - (unsigned int)(&struct2) << endl;
return 0;
}
输出结果(ubuntu gcc编译)
8
16
4
下面我们来分析下
1,自然对齐(默认对齐方式,是指按结构体的成员中 size 最大的成员对齐)
struct example1
{
short a;//2字节
long b;//4字节
};
所以sizeiof(example1)为8,a后面得填充两个空白字节
2.指定对齐
· 使用伪指令#pragma pack (n),编译器将按照 n 个字节对齐;
· 使用伪指令#pragma pack (),取消自定义字节对齐方式。
注意:如果#pragma pack (n)中指定的 n 大于结构体中最大成员的 size,则其不起作用,结构体
仍然按照 size 最大的成员进行对界。
#pragma pack(8)
struct example1
{
char a;
int b;
short c;
};
#pragma pack()
最大字节数为4所以不起作用大小为12
若顺序变为
#pragma pack(8)
struct example1
{
int b;
char a;
short c;
};
#pragma pack()
大小为8,以4字节对齐,a后填充一个空白字节,再接着2字节大小的c,所以大小为8
现在我们就可以很清楚的知道开始拿到题的答案由来了;
example1中最大字节为4指定对齐失效所以按4字节对齐大小为8;
example2中最大字节为example1中的long b所以也是按4字节对齐大小为16
由于example2按4字节对齐所以(unsigned int)(&struct2.struct1) - (unsigned int)(&struct2)
等于char c按4字节对齐的大小为4再举个例子,看看在默认对齐规则下,各结构体成员的对齐规则:
typedef struct A
{
char c; //1个字节
int d; //4个字节,要与4字节对齐,所以分配至第4个字节处
short e; //2个字节, 上述两个成员过后,本身就是与2对齐的,所以之前无填充
}; //整个结构体,最长的成员为4个字节,需要总长度与4字节对齐,所以, sizeof(A)==12
typedef struct B
{
char c; //1个字节
__int64 d; //8个字节,位置要与8字节对齐,所以分配到第8个字节处
int e; //4个字节,成员d结束于15字节,紧跟的16字节对齐于4字节,所以分配到16-19
short f; //2个字节,成员e结束于19字节,紧跟的20字节对齐于2字节,所以分配到20-21
A g; //结构体长为12字节,最长成员为4字节,需按4字节对齐,所以前面跳过2个字节,
//到24-35字节处
char h; //1个字节,分配到36字节处
int i; //4个字节,要对齐4字节,跳过3字节,分配到40-43 字节
}; //整个结构体的最大分配成员为8字节,所以结构体后面加5字节填充,被到48字节。故:
//sizeof(B)==48;
总结:1,默认对齐,按按结构体的成员中 size 最大的成员对齐
2,伪指令#pragma pack (n),编译器将按照 n 个字节对齐
3,有效对齐大小=min(指定对齐n,max(结构体的成员中 size),系统默认对齐值(gcc 4,vc 8));
4,大小和变量类型和声明顺序有关