两条规则
关于结构体内存对齐一般考虑两条规则,首先定义一些变量,
- 比如下面的_person结构体,其中的内部成员中,占据最大空间的设为var_max,它所拥有的字节空间为sizeof(var_max)。
- 那么整体的大小,即这个结构体总体字节数应该是sizeof(var_max)的整数倍。
- 结构体中一个成员变量b分配空间时,需要它的前一个成员变量a给出的下一个可用地址(也即b开始的地址,a结束的地址)是sizeof(b)的倍数,
- 比如说分配lastname的时候,firstname给出的下一个地址是(char *)&p + sizeof(char),它是sizeof(char)的整数倍,所以不需要补足,lastname以(char *)&p + sizeof(char)作为起始地址分配自己的空间。
- 而title分配自己空间时,lastname给它的地址是(char *)&p + 2*sizeof(char),它是sizeof(char *)的整数倍么?No,所以要地址补足,因此lastname给title的地址就变成了(char *)&p + 4*sizeof(char),lastname也就占据了3个字节的空间。
- 如果一个结构体a中有另一个结构体变量b,那么b的最大空间难道就按照sizeof(b)来算吗?经过实验发现不是的,其实最大空间原则只考虑所有C/C++的内部定义变量,也即char, char *, int这些变量的最大大小。同理,内存对齐的补足也是依照此原则。
一个例子
typedef struct _person{
char firstname;
char lastname;
char * title;
unsigned int age;
char sex;
struct spring ls;
}Person;
int main()
{
cout << sizeof(spring) << endl;
_person p;
int size[6];
size[0] = (char *)&p.lastname - (char *)&p.firstname;
size[1] = (char *)&p.title - (char *)&p.lastname ;
size[2] = (char *)&p.age - (char *)&p.title ;
size[3] = (char *)&p.sex - (char *)&p.age ;
size[4] = (char *)&p.ls - (char *)&p.sex ;
size[5] = sizeof(p) - ((char *)&p.ls - (char *)&p);
int sum = 0;
for (int i = 0 ; i < 6; i++)
{
sum += size[i];
cout << size[i] << endl;
}
cout << sizeof(p) << ":" << sum << endl;
}
上面的size[i]分别记录了_person中每一个成员变量占据的空间大小。
实际上_person占据的总字节大小与spring的大小是有关系的。
只有一个char的spring
首先我们定义一个简单的spring,它内部只有一个char,此时情况如何呢?
typedef struct spring{
char a;
};
分析结果:
firstname 一个字节
---------此时就是1个字节,满足sizeof(char)对齐标准-----------
lastname 一个字节+2个补足字节
---------此时就是4个字节,满足sizeof(char *)对齐标准-----------
title 四个字节
---------此时就是8个字节,满足sizeof(unsigned int)对齐标准-----------
age 四个字节
---------此时就是12个字节,满足sizeof(char)对齐标准-----------
sex 一个字节
---------此时就是13个字节,满足sprint中最大内置变量sizeof(char)对齐标准-----------
ls 一个字节+2个补足字节
---------此时就是16个字节,满足Person中最大内置变量sizeof(char*)对齐标准-----------
spring中有5个char
下面让spring中有5个char,此时会如何呢?
firstname,lastname,title,age是不受spring的影响的,所以没有任何变化。
因为spring中内置最大变量仍旧是char,所以sex也没变化。
所以
---------此时就是13个字节,满足sprint中最大内置变量sizeof(char)对齐标准-----------
ls 5个字节+2个补足字节
---------此时就是20个字节,满足Person中最大内置变量sizeof(char*)对齐标准-----------
spring中有1个char,1个int
typedef struct spring{
char a;
int b;
};
我们依然分析ls和sex两个。
---------此时就是12个字节,满足sizeof(char)对齐标准-----------
sex 一个字节+3个补足字节
---------此时就是16个字节,满足sprint中最大内置变量sizeof(int)对齐标准-----------
ls 8个字节
---------此时就是24个字节,满足Person中最大内置变量sizeof(char*)对齐标准-----------
spring中有1个char,1个int64
typedef struct spring{
char a;
uint64 b;
};
---------此时就是12个字节,满足sizeof(char)对齐标准-----------
sex 一个字节+3个补足字节
---------此时就是16个字节,满足sprint中最大内置变量sizeof(int64)对齐标准-----------
ls 16个字节
---------此时就是32个字节,满足Person中最大内置变量sizeof(int64)对齐标准-----------
下面我修改一下Person结构,把char *title改成char title,那么情况又会如何呢?
typedef struct _person{
char firstname;
char lastname;
char title;
unsigned int age;
char sex;
struct spring ls;
}Person;
firstname 一个字节
---------此时就是1个字节,满足sizeof(char)对齐标准-----------
lastname 一个字节+1个补足字节
---------此时就是2个字节,满足sizeof(char )对齐标准-----------
title 1个字节+1个补足字节
---------此时就是4个字节,满足sizeof(unsigned int)对齐标准-----------
age 四个字节
---------此时就是8个字节,满足sizeof(char)对齐标准-----------
sex 一个字节+7个补足字节
---------此时就是16个字节,满足sprint中最大内置变量sizeof(int64)对齐标准-----------
ls 16个子集
---------此时就是32个字节,满足Person中最大内置变量sizeof(int64)对齐标准-----------
如此一来sex的补足字节就多了很多哦