您的位置:首页 > 其它

struct union数据对齐和sizeof大小

2017-09-03 13:21 627 查看
什么是数据对齐?简单的说就是数据的起始地址必须是对齐值的整数倍。如果对齐值为N,则 起始地址 % N=0。

为什么要数据对齐?为了提高存取变量的效率。字节是内存空间分配的最小单位, 在程序中,我们定义的变量可以放在任何位置。其实不同架构 的CPU在访问特定类型变量时是有规律的,比如有的CPU访问int型变量时,会从偶数地址开始读取的,int类型占用4个字节(windows平台)。 0X0000,0X0004,0X0008…..这样只需要读一次就可以读出Int类型变量的值。相反地,则需要读取二次,再把高低字节相拼才能得到 int类型的值,这样子看的话,存取效率当然提高了。  

通常写程序的时候,不需要考虑这些情况,编译都会为我们考虑这些情况,除非针对那些特别架构的 CPU编程的时候的则需要考虑 。当然用户也可以手工控制对齐方式。

数据对齐可以分为几种类别:

1 基本数据类型的数据对齐

基本类型的数据对齐值是其本身的大小。

类型对齐值(字节)
char1
short2
int4
float4
double8
指针4(32位) 8(64位)
2 struct/class的自身对齐值。对于结构体和类的自身对齐值是所有成员中最大的自身对齐值。

结构体和类的对齐规则:先将数据成员对齐,在将结构体和类自身对齐,最终大小与数据成员顺序 有关。

3 union的自身对齐值。union的自身对齐值是所有成员中最大的对齐值。union的对齐规则,只需要union自身对齐,不需要数据成员对齐,最终大小与数据成员顺序无关。

4 指定对齐值。使用#pragma pack(n)指定对齐值为n,使用#pragma pack() 回复默认对齐值。

5 有效对齐值。对于指定了对齐值的代码, 有效对齐值=min(类/结构体/成员的自身对齐值, 指定对齐值)

未指定对齐值时,默认的对齐值一般为8。

有效对齐值决定了数据存放的方式,sizeof运算符是根据有效对齐值计算大小的。

举例分析:

union U1
{
char a[9];
int b;
double c;
};

union U2
{
int b;
char a[9];
double c;
};

union U3
{
double c;
int b;
char a[9];

};


U1,U2,U3的sizeof的值都是16。 union的大小是所有成员中内存最大的大小。所以是9。因为对齐问题,union自身的对齐值是所有成员对齐的最大值 8。所以要填充 9个字节, 最终的大小为16。

从这个例子可以看出:union不需要成员数据对齐, 最终大小与成员的顺序无关。

struct A
{
char a[9];
short b;
int c;
};

struct B
{
short b;
int c;
char a[9];

};

struct C
{
int c;
char a[9];
short b;
};


结果值分别为16 20 16。

先看A,首先是成员的对齐。 a需要9个字节,char的对齐值是2,所以填充1个字节,9 + 1 + 2 = 12 个字节。int的对齐值为4,12 % 4 = 0,所以 大小为 12 + 4 = 16。在看 struct的对齐。struct的对齐值为最大对齐值4。 16 % 4 = 0。 最终大小为16。

在看B,首先是成员的对齐。short需要2字节,int的对齐值为4,所以填充2个字节,2 + 2 + 4 = 8。 char的对齐值为1(与数组无关,不是9), 8 + 9 = 17。再看struct的对齐值为4,填充3个字节,17 + 3 = 20。

再看C, int 需要4个字节, a 需要9个字节, 4 + 9 = 13。 short需要2个字节, 4 + 9 + 1 + 2 = 16。 再看struct的对齐,对齐值为4, 16 % 4 = 0。 最终结果为4。

从这个例子可以看出:struct需要先对其数据成员,在对其struct本身。最终大小与成员顺序有关。

书写结构体时,建议按照数据类型(对齐值)从小到大书写。

#pragma pack(2)

union U1 { char a[9]; int b; double c; }; union U2 { int b; char a[9]; double c; }; union U3 { double c; int b; char a[9]; };

struct A { char a[9]; short b; int c; }; struct B { short b; int c; char a[9]; }; struct C { int c; char a[9]; short b; };


结果值分别为10 10 10 16 16 16.

先看三个union。大小都为9,成员中最大的对齐值为8,指定的对齐值为2, 有效对齐值为2。union本身对齐值为2。 则 结果为9+1=10。

再看A。a需要9个字节,short需要2个字节,填充一个字节,9+1+2= 12。int的对齐值为4,指定为2,有效对齐值为2。 所以 12+4 =16。再看结构体本身,成员最大对齐值为4,指定为2, 有效对齐值为2, 16 % 2 = 0。最终结果为 16。

再看B。short需要2字节,int有效对齐值为2,2 + 4 = 6, char需要9字节, 6+ 9=15。 再看struct本身对齐。有效对齐值为2, 15+ 1 = 16。

再看C。int 占4字节,数组占9字节, 4+ 9 = 13, 填充一个字节, 13+1 + 2 = 16. 再看struct本身对齐。满足要求。最终结果为16。

如果是嵌套的情况呢?

举例分析:

union U
{
char a[9];
int b;
double c;
};

struct A
{
U u;
char a[9];
short b;
int c;
};

struct B
{
short b;
U u;
int c;
char a[9];

};
struct C
{
int c;
char a[9];
short b;
struct A aa;
};


A B C最终大小为:32 40 48;

分析:根据前面的分析,union U的大小为16,对齐值为 8。

A: U大小为16, char数组大小为9, 16 + 9 = 25。填充1个字节,放short, 25 + 1 + 2 = 28。 再放int, 28+4=32。struct本身的对齐值为8, 32 % 8 = 0,满足要求。

B:short占2字节, U占16,最气质为8,所以填充6字节, 2 + 6 + 16 = 24。放int, 24 + 4 = 28。放char数组,28+9=37。 struct本身有效对齐值为8,填充3字节, 37+3 = 40.

C: A的大小为32, 有效对齐值为8。 int 占4字节, char数组占9字节,4 +9=13。填充一个字节,放short,13+1+2 = 16。 放A,16+32 = 48。struct本身对齐也满足。

总结:对于嵌套类型,先按照规则分别计算每个数据成员的大小和对齐值,在考虑结构体本身的对齐。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  sizeof struct union 嵌套