关于数据对齐和填充的另一个困惑

Yet another confusion about data alignment and padding

本文关键字:填充 另一个 对齐 于数据 数据      更新时间:2023-10-16

我一直在读关于数据对齐和结构填充的文章。我从这里开始,只是为了表达我的理解,我可以说T类型的元素或数据e是自然对齐的,如果它的地址a是它的数据大小[sizeof T]的倍数,

让我们考虑

struct test{
short a;
char b;
};

由于struct test的最大排列(short(,constexpr auto size = sizeof test为4

然后我来到这里,第一个答案很好地解释了数据对齐,作者使用了这个例子

data1: "ab"
data2: "cdef"
|a b c d|     |e f 0 0|

假设内存访问粒度为4字节,我将在这里假设data12字节,data24 byte,因为data2从奇数地址开始,或者它的地址不是4 byte的倍数,这被认为是未对齐的数据,所以访问data2将根据体系结构产生不同的效果。

这里有填充,通过添加junkies(或纯0(使data2自然对齐,最后我们有

|a b 0 0| |c d e f|

到目前为止还可以,现在让我们将这两个数据包装到一个结构中

struct wrap{
data1: "ab"
data2: "cdef"
};

现在,通过考虑最大对齐,wrap大小将变为具有两字节填充的8

在这里,在struct wrap的情况下,无论是有填充还是没有填充,处理器实际上需要两个周期(给定WORD大小为4字节(来获取wrap对象,对吗?那么我们为什么需要填充呢?

无填充:

|a b c d| |e f 0 0|

假设处理器获取了8字节的wrap objectdata1是两个字节,因此它可以保存"ab",剩余的将被截断(就像填充位将被截断的方式一样(并且data2可以从其地址(读取"cdef"(读取连续的4个字节,其余的都被截断了,那么为什么我们需要在这里填充,或者我只是弄错了?

第二个问题或多或少类似于上述

struct test2{
short a; //2 byte
char _3,_4,_5,_6,_7,_8,_9,_10,_11 ;
};

sizeof test2将给出12,如果现在内存访问粒度(更改WORD=8(是8字节,那么test2的对象将占用两个WORD,无论是否填充,它都将占用两次WORD,所以无论test2的对齐如何,都需要两个周期来获取其对象,如果是这种情况,为什么填充在这里很重要?为什么12而不是11都需要在8字节的边界中有两个循环?

最后一个问题,

struct final{
char a;
int b;
};

假设struct final被打包(没有对齐(,vartest::b将被放置在奇数地址

记忆(只是一种理论表示(

0          1          2          3          4          5          6         7
tets::a:1  test::b:1  test::b:2  test::b:3  test::b:4

test::b:xam此处不是指位字段

我已经了解到,只要我通过`.使用对象访问test::b。或者->'它会很好,但当我把它的地址

int * p = &(test::b) ; (void)*p;此语句要么性能受损,要么崩溃。

同样,如果WORD=8字节,那么struct final的对象将在一个周期内进入内存,假设指针p保持地址1,这是奇数,但难道仅仅是*p的差异就不能将从地址1开始到其指向元素类型(4字节(的位复制到内存中吗?为什么这里有问题?我错过了什么?

数据错位的问题与整个结构的加载/存储无关。它显示时可以访问各个字段。

当字段未对齐时,需要两次读/写加上字节重排,而不是一次。填充结构更大,我们不介意。