关于结构体字节对齐的一些问题

 

#

字节对齐的目的

字节对齐的作用不仅是便于cpu快速访问,同时合理的利用字节对齐可以有效地节省存储空间。对于32位机来说,4字节对齐能够使cpu访问速度提高,比如说一个long类型的变量,如果跨越了4字节边界存储,那么cpu要读取两次,这样效率就低了。但是在32位机中使用1字节或者2字节对齐,反而会使变量访问速度降低。所以这要考虑处理器类型,另外还得考虑编译器的类型。在vc中默认是4字节对齐的,GNU gcc 也是默认4字节对齐。

字节对齐的基本原则

如下三条

  1. 结构体变量的首地址能够被其最宽基本类型成员的大小所整除;
  2. 结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal adding);
  3. 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节(trailing padding)。

举一个简单的例子:

struct node
{
    double d;
    int a;
    int b;
    char c;
};

首先double d的偏移是0,占用8字节;int a的偏移是8,可以被a的长度(4字节)整除,所以在偏移8的位置占用4字节;int b的偏移是12,同样可以整除;char c的偏移是16,可以被c的长度(1)整除,所以在偏移16的位置占用1字节。这时整个结构体占用了17字节的长度,不能被最长的成员(double类型,8字节)整除,所以必须再填充7字节。从而整个结构体的长度为24字节。

我们把之前的例子稍微变一下:

struct node
{
    int a;
    int b;
    char c;
    double d;
};

这时a占用4字节,b占用4字节,c在偏移8的位置占用1字节,这时的偏移是9,无法被double的长度整除,所以需要填充7字节,最后占用24字节,刚好可以被结构体最长元素(double)整除。

参考文献: