struct union数据对齐和sizeof大小

什么是数据对齐?简单的说就是数据的起始地址必须是对齐值的整数倍。如果对齐值为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本身对齐也满足。

总结:对于嵌套类型,先按照规则分别计算每个数据成员的大小和对齐值,在考虑结构体本身的对齐

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhengjihao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值