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

时间:2018-07-28 14:27:55

标签: c++ c memory

我一直在阅读有关数据对齐和结构填充的信息。我从here开始,为了表达我的理解,我可以说类型为{{1的元素或数据e }}如果其地址T是其数据大小的倍数[a

自然对齐

考虑一下

sizeof T
由于struct test{ short a; char b; }; 的最大对齐方式(constexpr auto size = sizeof test),

struct test为4

然后我去here,第一个答案很好地解释了数据对齐,作者使用了这个示例

short

鉴于内存访问的粒度为4字节,我将在此处做出一个假设,例如data1: "ab" data2: "cdef" |a b c d| |e f 0 0| data1字节,而2data2,因为4 byte从奇数地址开始,或者它的地址不是data2的倍数(被认为是未对齐数据),因此根据架构,访问4 byte会有不同的效果。< / p>

在这里填充以使data2通过添加垃圾邮件(或纯0)自然对齐,最后我们有了

data2

到目前为止,现在让我们将两个数据包装成一个结构

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

现在,通过考虑最大对齐方式,struct wrap{ data1: "ab" data2: "cdef" }; 的大小将变为wrap,并且填充了两个字节。

在这里,对于8,是填充还是不填充,处理器实际上需要两个周期(给定WORD大小为4字节)来获取struct wrap对象? 那么为什么我们需要填充?

没有填充:

wrap

假定处理器获取了8个字节的|a b c d| |e f 0 0|wrap object是两个字节,因此它可以容纳剩余的“ ab”将被截断(就像填充位将被截断一样) 并且data1可以从其地址读取连续的4个字节(读为“ cdef”),其余部分被截断了,那么为什么我们需要在此处填充,还是我弄错了?

与上述基本相似的第二个问题

data2

struct test2{ short a; //2 byte char _3,_4,_5,_6,_7,_8,_9,_10,_11 ; }; 将给出12,现在内存访问粒度(更改WORD = 8)为8字节,则sizeof test2的对象将占用两个WORD,无论是否填充它会占用两个WORD,因此无论test2的对齐方式如何,都需要两个周期来获取其对象,如果是这种情况,为什么填充在这里很重要?为什么12个而不是11个,尽管两者都需要在8字节边界内两个周期?

最后一个问题

test2

假设struct final{ char a; int b; }; 被打包(不对齐),并且变量struct final将被放置在奇数地址

内存(只是理论上的表示)

test::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。或->'就可以了,但是当我拿到地址时

test::b:x该语句将导致性能下降或崩溃。

同样,如果WORD = 8个字节,则int * p = &(test::b) ; (void)*p;的对象将在一个周期内进入内存,并且假设指针struct final拥有地址p,这是奇数,但是不能仅凭1的引用就将地址*p开始的所有位复制到指向元素类型(4字节)的指针到内存中?为什么这里有问题?我一直想念的是什么?

1 个答案:

答案 0 :(得分:3)

数据未对齐的问题与整个结构的加载/存储无关。它会显示对各个字段的访问权限。

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