1.示例
我们来一个例子来看,结构体对齐后,结构体大小的计算
#include<iostream>
using namespace std;
#pragma pack(2)
struct Test {
int a;
char b;
short c;
char d;
};
int main()
{
Test a;
cout << sizeof(a) << endl;
cout << &a<< endl;
return 0;
}
这个例子中,Test为结构体,这个结构体的声明为:
struct Test {
int a;
char b;
short c;
char d;
};
这个结构体中有四个成员,分别为整型的a,字符型的b,short型的c,字符型的d
一般来说short是short int的缩写,long是long int的缩写,一般来说,short,int,long这三者的大小是:short<=int<=long,
32位编译系统:short占两字节,int占四字节,long占四字节,与int相同。
64位编译系统:short占两字节,int占四字节,long占8字节
2.结构体对齐的规则
计算结构体大小时,字节对齐的要求以及对齐单位的大小由以下规则给出。
对齐单位由以下规则进行确定:
1> 结构体变量的首地址能够被结构体内其最宽基本类型成员的大小所整除;
2> 结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal adding);
3>程序员可以使用预处理指令# parama pack(n)来设定默认对齐单位大小,其中n值就是设置的大小(值位1,2,4,8…),数据成员本身也有一个字节大小,编译器会选择这两个中小的那个数值作为此成员的对齐大小。
注:因为是按照顺序存储结构体中的成员,所以即使结构体中的数据成员完全一样,而他们的相对位置顺序不一样的话,那么他们所占的大小也很可能不同。
3.结构体大小的计算
以上面例子为例。
(1)a占4字节,大于预设的2。将2作为对齐成员a的对齐大小。假设成员a起始地址为0,0能被结构题中最大数据类型4整除,符合【结构体对齐的规则】中的规则1。所以a存储的位置区间为[0,3]。
(2)b占1字节,小于预设的2。1作为对齐大小,挨着a存储b,那么起始地址为4,4能被1整除,所以存储的b位置区间为[4]。
(3)c占2字节,所以对齐大小为2,挨着c存储,起始地址为5,而5不是2的倍数,6是2的倍数,根据【结构体对齐的规则】中的规则2,需要补一位,从6开始存储c,所以存储c的位置区间为[6,7]
(4)字节d占1字节,将1作为对齐大小,8是1的倍数,挨着c存储d,所以存储d的位置区间为[8]。而存储完最后一个数据成员d之后的地址为9,9不是2的倍数,需要补齐1个字节大小。d的存储空间加上一个补齐的空间,地址为[8,9]使得下一个地址为10,能被2整除。
最终,此例子中结构体大小为size=10.
如果#pragma pack(n),n设置为1,则此结构题大小为8。等于所有数据成员大小的简单和。
References: