计算机取数据最低一个字节,基本都是双字,因此如果数据没有对齐,有时候一个数可能分布在多个字节中,内存对齐是为了加快计算机的取数速度,否则就得多花指令周期。下面是 sizeof 的一些对齐知识。
对齐基本规则
- 结构体变量的首地址能够被其最宽基本类型成员的大小所整除。
- 结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal adding)。
- 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节(trailing padding)。
sizeof 类或者结构体
- sizeof 结构体以及类的实例是同一结果,sizeof 类本质上就是计算类的实例大小。
- sizeof 一个空类(或者空结构体),结果是 1。空类,没有任何成员变量或函数,即没有存储任何内容,所以大小为 0,但是由于空类仍然可以实例化,一个类能够实例化,编译器就需给它分配内存空间,来指示类实例的地址,所以编译器就为类默认添加了一个隐藏的字节。
- sizeof 只考虑类的成员变量,不需要考虑成员函数,但是虚函数会增加虚表指针的空间(虚表指针在对象内存的首位置)。
- 类的静态成员变量不计入 sizeof 大小。
- 子类继承了父类的私有成员,子类虽然不能访问,但是 sizeof 仍需要计算这一部分。
- 子类继承一个空类,sizeof 则大小为子类的大小(子类也是空类,则 sizeof 为 1)
- 当上述的类虚继承一个空类(是不是空都无所谓),那么虚继承的子类中需要添加一个虚基类指针(虚继承就是类似虚函数的实现来实现基类共享)
- 多继承中如果多个父类有虚函数,则会有多个虚函数表,子类自己定义的虚函数不会生成虚函数表,单继承时并入父类的虚表,多继承时并入继承的第一个父类的虚表中。
sizeof 数组
- sizeof 数组和指针是不一样的,sizeof 计算的是数组的大小。
- C 风格的 char 数组,如果不指定数组的长度,计算结果是字符个数 +1,包含 \0 的结束位。
sizeof union
联合体的内存是重叠的,则 sizeof 就是最大数据成员的大小。
利用 sizeof 获取结构体某个成员的偏移量
思路:将 0 地址转换为结构体的指针,然后获取成员的地址即偏移量
#define offsetof(s,m) (size_t)&(((s *)0)->m)