为什么"[0] byte"在结构中的位置很重要? [英] Why position of `[0]byte` in the struct matters?

查看:103
本文介绍了为什么"[0] byte"在结构中的位置很重要?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

[0]byte不应占用任何内存空间.但是这两个结构的大小不同.

[0]byte in golang should not take any memory space. But these two structs have different sizes.

type bar2 struct {
    A int
    _ [0]byte
}

type bar3 struct {
    _ [0]byte
    A int   
}

那为什么[0]byte的位置在这里很重要?

So why the position of [0]byte matters here?

顺便说一句,我使用unsafe.Sizeof()方法检查结构大小.请参见完整示例.

By the way, I use unsafe.Sizeof() method to check the struct size. See the full example .

推荐答案

这是由于 tricky 填充引起的.

首先,请允许我稍微重命名结构和字段,以便更轻松地讨论它们:

First please allow me to slightly rename the structs and fields so it'll be easier to talk about them:

type bar1 struct {
    A [0]byte
    I int
}

type bar2 struct {
    I int
    A [0]byte
}

这当然不会更改大小和偏移量,可以在转到游乐场上进行验证a>:

This of course doesn't change the size and offsets as can be verified on the Go Playground:

bar1 size:     4
bar1.A offset: 0
bar1.I offset: 0

bar2 size:     8
bar2.I offset: 0
bar2.A offset: 4

类型为[0]byte的值的大小为零,因此在bar1中不为第一个字段(bar1.A)保留任何空间,并以0布置bar1.I字段的布局是完全有效的偏移量.

The size of a value of type [0]byte is zero, so it is perfectly valid in bar1 to not reserve any space for the first field (bar1.A), and lay out the bar1.I field with 0 offset.

问题是:为什么在第二种情况下(使用bar2)编译器不能做同样的事情?

The question is: why can't the compiler do the same in the 2nd case (with bar2)?

一个字段的地址必须位于为前一个字段保留的存储区之后.在第一种情况下,第一个字段bar1.A的大小为0,因此第二个字段的偏移量可能为0,因此不会与第一个字段重叠".

A field must have an address that must be after the memory area reserved for the previous field. In the first case the first field bar1.A has 0 size, so the 2nd field may have 0 offset, it will not "overlap" with the first field.

对于bar2,第二个字段的地址(和偏移量)不能与第一个字段重叠,因此其偏移量不能小于int的大小,对于int,它的大小为4个字节. 32位体系结构(如果是64位arch,则为8字节).

In case of bar2, the second field cannot have an address (and therefore an offset) that overlaps with the first field, so its offset cannot be less than the size of int which is 4 bytes in case of 32-bit architectures (and 8 bytes in case of 64-bit arch).

这似乎还是可以的.但是,由于bar2.A的大小为零,为什么结构bar2的大小不能仅仅是:4个字节(或64位arch中的8个字节)?

This still seems ok. But since bar2.A has zero size, why can't the size of the struct bar2 be just that: 4 bytes (or 8 in 64-bit arch)?

这是因为,采用具有0个大小的字段(和变量)的地址完全有效.好吧,那又怎样呢?

This is because it is perfectly valid to take the address of fields (and variables) that have 0 size. Ok, so what?

对于bar2,编译器必须插入4(或8)字节的填充,否则采用bar2.A字段的地址将指向保留用于存储的区域 bar2类型的值.

In case of bar2, the compiler has to insert a 4 (or 8) byte padding, else taking the address of a bar2.A field would point outside of the memory area reserved for a value of type bar2.

例如,不填充的情况下,值bar2的地址可能为0x100,大小为4,因此为结构值保留的内存的地址范围为0x100 .. 0x103. bar2.A的地址为0x104,即在该结构的内存之外.对于此结构的数组(例如x [5]bar2),如果该数组从0x100开始,则x[0]的地址将为0x100x[0].A的地址将为0x104,并且后续元素x[1]也将是0x104,但这是另一个结构值的地址!不酷.

As an example, without padding a value of bar2 may have an address of 0x100, size 4, so memory reserved for the struct value has address range 0x100 .. 0x103. Address of bar2.A would be 0x104, that is outside of the struct's memory. In case of an array of this struct (e.g. x [5]bar2), if the array starts at 0x100, address of x[0] would be 0x100, address of x[0].A would be 0x104, and address of the subsequent element x[1] would also be 0x104 but that's the address of another struct value! Not cool.

为避免这种情况,编译器会插入一个填充(根据拱形为4或8个字节),因此采用bar2.A的地址不会导致地址超出结构的内存,否则可能会引发问题并引起有关垃圾回收的问题(例如,如果仅保留bar2.A的地址,但不保留该结构或指向它的其他指针或它的其他字段,则不应对整个结构进行垃圾回收,但是由于没有指针指向它内存区域,这样做似乎是有效的).插入的填充为4(或8)字节,因为规范:大小和对齐保证:

To avoid this, the compiler inserts a padding (which will be 4 or 8 bytes depending on the arch), so that taking the address of bar2.A will not result in an address being outside of the struct's memory, which otherwise could raise questions and cause problems regarding garbage collection (e.g. if only address of bar2.A is kept but not the struct or another pointer to it or its other fields, the whole struct should not be garbage collected, but since no pointer points to its memory area, it would seem to be valid to do so). The inserted padding will be 4 (or 8) bytes, because Spec: Size and alignment guarantees:

对于结构类型的变量x:unsafe.Alignof(x)x的每个字段f的所有值unsafe.Alignof(x.f)中最大的值,但至少为1.

For a variable x of struct type: unsafe.Alignof(x) is the largest of all the values unsafe.Alignof(x.f) for each field f of x, but at least 1.

如果是这样,添加一个额外的int字段将使两个结构的大小相等:

If this is so, adding an additional int field would make the size of both structs equal:

type bar1 struct {
    I int
    A [0]byte
    X int
}

type bar2 struct {
    A [0]byte
    I int
    X int
}

确实,它们在32位架构上都具有8个字节(在64位架构上具有16个字节)(请在去游乐场):

And truly they both have 8 bytes on 32-bit arch (and 16 bytes on 64-bit arch) (try it on the Go Playground):

bar1 size:     8
bar1.I offset: 0
bar1.A offset: 4
bar1.X offset: 4

bar2 size:     8
bar2.A offset: 0
bar2.I offset: 0
bar2.X offset: 4

请参阅相关问题:结构如果字段顺序不同,则具有不同的大小

这篇关于为什么"[0] byte"在结构中的位置很重要?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆