Toriyung

导航

字节对齐问题

概念:

  CPU每一次读取数据是按照固定起始地址字节长度读取的

  比如32位(4字节)的CPU读取起始地址为0x0000,那么其读取数据地址顺序应该是0x0000~0x0003,然后0x0004~0x0007

  当有个4字节数据存储在0x0002~0x0005上,即起始地址为0x0002,为了读取完整,CPU需要分别读取0x0000~0x0003和0x0004~0x0007,这样一个字节的数据读取就进行了两个字节的CPU读取,效率低且浪费资源。

  假如该数据存储为0x0000或0x0004甚至0x0008,CPU只需要分别以0x0000或0x0004或0x0008为起始地址读取一次即可,不难看出,其由CPU的固定起始地址数据存放起始地址相对位置有关,其量化表示可为:数据存放起始地址能被字节长度所整除,则效率最大化。如例子中0x0002 % 4 = 2,明显不整除,而如果数据存储在如0x0004或0x0008为起始地址,则可以整除。

 

结构体的对齐规则:

  按最大类型的倍数

  首地址为自身大小的倍数

这里解释下为什么需要按最大类型的倍数,如下例子

struct MyStruct1 {
 char b;    // 本来1个字节 + 7个字节padding
 double a;  // 8 个字节
 int c;     // 本来 4 个字节,但是整体要按 8 字节对齐,所以 4个字节padding
  // 总共: 8 + 8 + 8 = 24
};

之所以int c后要按最大的double的8字节进行填充,是因为考虑到多个结构体实例的对齐,加入int c后不补充,则单个结构体的占用为0x00~0x14(假如从0x00开始)共二十个字节,那么如果有下一个结构体就是从0x15开始,

该结构体内部的字节排布则是

char b : 0x15~0x1D

double a : 0x1E~xxx,可以看到此时类型为double的a变量的首地址无法被8整除(0x1E=0d30,30无法被8整除)

 

 

 

操作(这里仅讨论向下对齐):

   使用“与”操作抹去相对高位。如0d0033即0b00100001,对于4字节对齐则与上~(0x0003)即抹除不到整4的值,得到0d0032;对于8字节对齐则与上~(0x0007)即抹除不到整8的值,得到0d0032,以此类推

 

 

参考:

  https://blog.csdn.net/Demondai999/article/details/121640212

  http://t.zoukankan.com/grooovvve-p-14158927.html

posted on 2022-11-01 23:59  Toriyung  阅读(57)  评论(0编辑  收藏  举报