深入理解类的填充规则
struct/class中的成员变量所占总大小不是简单地将各个成员变量的大小相加,而是要考虑到读取效率,有时需要添加填充字节。
比如有些平台每次读都是从偶地址开始,如果一个int型(假设为32位系统)如果存放在偶地址开始的地方,那 么一个读周期就可以读出这32bit,而如果存放在奇地址开始的地方,就需要2个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该32bit数据。
填充规则: (1)结构体变量的首地址能够被其最宽基本类型成员的大小所整除;
(2)结构体每个成员相对于结构体首地址的偏移量都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节
(3)结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节。
判断一个类的大小通常用到规则(2)和(3)。
例子1:基本分析
class Coo { char c; short s; int i; short s2; };
首先c的偏移量是0,而0是1的整数倍,因此不用加填充;s的偏移量是1,而1不是2的整数倍,因此要填充1;
i的偏移量是4,而4是4的整数倍,因此不用填充;s2的偏移量是8,而8是2的整数倍,因此不用填充。
最后,在类coo中,最宽基本类型是int,大小是4,而目前我们的类大小为: 1 (+1) + 2 + 4 + 2 = 10,不是4的整数倍,因此要在最后填充2。
例子2:空类
class Coo {};
空类的大小是1。如果coo的大小是0,就无法区别其他的空类了。
例子3:有静态成员
class Coo { static int i; };
类的大小是1。静态数据成员不属于实例的一部分,而是放到了全局数据区。
例子4:类嵌套
class CooIn { int i; short s; int i2; }; class Coo{ char c; CooIn ci; double d; };
首先分析被嵌套的CooIn的大小,易得为12,且最宽数据成员大小为4。然后以ci为分界点,前面的大小要为4的整数倍,因此为1 + 3,而后面
的分析就没有什么特殊性了。注意,不能把CooIn在Coo内展开为
class Coo{ char c; int i; short s; int i2; double d; };
要将CooIn看作一个整体,其传输单位为4,因此ci前在加上CooIn时,要保证是4的整数倍