加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

memory – 如果字段顺序不同,则Struct具有不同的大小

发布时间:2020-12-16 10:12:17 所属栏目:百科 来源:网络整理
导读:package mainimport ( "fmt" "unsafe")type A struct { a bool b int64 c int}type B struct { b int64 a bool c int}type C struct {}func main() { // output 24 fmt.Println(unsafe.Sizeof(A{})) // output 16 fmt.Println(unsafe.Sizeof(B{})) // output
package main

import (
    "fmt"
    "unsafe"
)

type A struct {
    a bool
    b int64
    c int
}

type B struct {
    b int64
    a bool
    c int
}

type C struct {
}

func main() {
    // output 24
    fmt.Println(unsafe.Sizeof(A{}))

    // output 16
    fmt.Println(unsafe.Sizeof(B{}))

    // output 0
    fmt.Println(unsafe.Sizeof(C{}))
}

>结构A和B具有相同的字段,但如果以不同的顺序指定,则它们会产生不同的大小.为什么?
> struct C的大小为零.系统为a:= C {}分配了多少内存?

谢谢.

解决方法

1.结构尺寸

TL; DR; (摘要):如果重新排序字段,将使用不同的隐式填充,并且隐式填充将计入结构的大小.

请注意,结果取决于目标体系结构;您发布的结果在GOARCH = 386时适用,但当GOARCH = amd64时,A {}和B {}的大小将为24个字节.

必须对齐struct的字段地址,int64类型的字段地址必须是8个字节的倍数. Spec: Package unsafe:

Computer architectures may require memory addresses to be aligned; that is,for addresses of a variable to be a multiple of a factor,the variable’s type’s alignment. The function Alignof takes an expression denoting a variable of any type and returns the alignment of the (type of the) variable in bytes.

int64的对齐是8个字节:

fmt.Println(unsafe.Alignof((int64(0)))) // Prints 8

因此,在A的情况下,因为第一个字段是bool,所以在Aa之后有一个7字节的隐式填充,因此类型为int64的Ab可以在8的倍数的地址上开始.这(需要7字节的填充)确保结构本身与一个8的倍数的地址对齐,因为它是所有字段的最大尺寸.见:Spec: Size alignment guarantees:

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.

在B的情况下(如果你的情况是GOARCH = 386),在bool类型的Ba字段之后只有一个3字节的隐式填充,因为这个字段后跟一个int类型的字段(大小为4字节) )而不是int64.

如果GOARCH = 386,则int的对齐为4个字节,如果GOARCH = amd64,则为8个字节:

fmt.Println(unsafe.Alignof((int(0))))   // Prints 4 if GOARCH=386,and 8 if GOARCH=amd64

使用unsafe.Offsetof()找出字段的偏移量:

// output 24
a := A{}
fmt.Println(unsafe.Sizeof(a),unsafe.Offsetof(a.a),unsafe.Offsetof(a.b),unsafe.Offsetof(a.c))

// output 16
b := B{}
fmt.Println(unsafe.Sizeof(b),unsafe.Offsetof(b.b),unsafe.Offsetof(b.a),unsafe.Offsetof(b.c))

// output 0
fmt.Println(unsafe.Sizeof(C{}))

var i int
fmt.Println(unsafe.Sizeof(i))

如果GOARCH = 386则输出(在Go Playground上尝试):

24 0 8 16
16 0 8 12
0
4

如果GOARCH = amd64则输出:

24 0 8 16
24 0 8 16
0
8

2.零尺寸值

Spec: Size alignment guarantees:

A struct or array type has size zero if it contains no fields (or elements,respectively) that have a size greater than zero. Two distinct zero-size variables may have the same address in memory.

因此规范只是提示使用相同的内存地址,但这不是必需的.但目前的实施遵循它.也就是说,不会为大小为零的类型的值分配内存,这包括空结构struct {}和零长度的数组,例如,[0] int,或其元素大小为零(并且具有任意长度)的数组.

看这个例子:

a := struct{}{}
b := struct{}{}
c := [0]int{}
d := [3]struct{}{}

fmt.Printf("%p %p %p %p %p",&a,&b,&c,&d,&d[2])

输出(在Go Playground上尝试):所有地址都相同.

0x21cd7c 0x21cd7c 0x21cd7c 0x21cd7c 0x21cd7c

有关一个有趣且相关的主题,请阅读:Dave Cheney: Padding is hard

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读