Go语言中结构体的大小

crcmnpdw  于 2022-12-07  发布在  Go
关注(0)|答案(6)|浏览(149)

我正在研究Go语言,它看起来很有前途。我正在尝试弄清楚如何得到一个go结构体的大小,例如类似于

type Coord3d struct {
    X, Y, Z int64
}

当然,我知道它是24字节,但我想通过编程来了解它。
你有什么办法吗?

k10s72fa

k10s72fa1#

为了不引起初始化结构的开销,使用指向Coord3d的指针会更快:

package main

import (
    "fmt"
    "unsafe"
)

type Coord3d struct {
    X, Y, Z int64
}

func main() {
    var dummy *Coord3d
    fmt.Printf("sizeof(Coord3d) = %d\n", unsafe.Sizeof(*dummy))
}
aelbi1ox

aelbi1ox2#

/*
    returns the size of any type of object in bytes
*/

func getRealSizeOf(v interface{}) (int, error) {
    b := new(bytes.Buffer)
    if err := gob.NewEncoder(b).Encode(v); err != nil {
        return 0, err
    }
    return b.Len(), nil
}
rjjhvcjd

rjjhvcjd3#

Roger已经演示了如何使用unsafe包中的SizeOf方法。请确保在使用函数返回的值之前阅读以下内容:
该大小不包括x可能引用的任何内存。例如,如果x是一个切片,则Sizeof返回切片描述符的大小,而不是切片引用的内存的大小。
除此之外,我还想解释一下如何使用几个简单的规则来轻松计算任何结构体的大小,以及如何使用一个有用的service来验证你的直觉。
大小取决于它所包含的类型以及字段在结构中的顺序(因为将使用不同的填充)。这意味着具有相同字段的两个结构可以具有不同的大小。
例如,此结构的大小为32

struct {
    a bool
    b string
    c bool
}

并且稍微修改将具有24大小(**25%**的差异仅仅是由于字段的更紧凑的排序)

struct {
    a bool
    c bool
    b string
}

第一次
如图所示,在第二个示例中,我们删除了一个填充,并移动了一个字段以利用之前的填充。对齐可以是1、2、4或8。填充是用于填充变量以填充对齐的空间(基本上是浪费的空间)。
了解这一规则并记住:

  • bool,int 8/uint 8取1个字节
  • int 16、uint 16 - 2个字节
  • 整数32、单位整数32、浮点数32 - 4个字节
  • int 64、uint 64、float 64、指针- 8个字节
  • 字符串- 16字节(2个8字节对齐)
  • 任何一个切片都需要24个字节(3个8字节的对齐),所以[]bool[][][]string是相同的(不要忘记重读我在开头添加的引文)
  • 长度为n的数组采用n * 类型,其采用字节。

有了填充、对齐和字节大小的知识,您可以快速找出如何改进您的结构(但这对verify your intuition using the service仍然有意义)。

sqougxex

sqougxex4#

import unsafe "unsafe"

/* Structure describing an inotify event.  */
type INotifyInfo struct {
    Wd     int32  // Watch descriptor
    Mask   uint32 // Watch mask
    Cookie uint32 // Cookie to synchronize two events
    Len    uint32 // Length (including NULs) of name
}

func doSomething() {
    var info INotifyInfo
    const infoSize = unsafe.Sizeof(info)
    ...
}

**注意:**OP错误。unsafe.Sizeof在示例Coord3d结构上返回24。请参阅下面的注解。

ilmyapht

ilmyapht5#

TotalSize也是一个选项,但请注意,它与unsafe在行为上略有不同。Sizeof:二进制。TotalSize包括切片内容的大小,但不安全。Sizeof只返回顶级描述符的大小。下面是如何使用TotalSize的示例。

package main

import (
    "encoding/binary"
    "fmt"
    "reflect"
)

type T struct {
    a uint32
    b int8
}

func main() {
    var t T
    r := reflect.ValueOf(t)
    s := binary.TotalSize(r)

    fmt.Println(s)
}
vlurs2pr

vlurs2pr6#

这可能会改变,但我最后发现有一个与结构对齐相关的突出的编译器错误(bug260.go)。最终结果是打包一个结构可能不会给予预期的结果。这是针对编译器6 g版本5383 release.2010-04-27 release。它可能不会影响你的结果,但它是需要注意的。
更新:go测试套件中唯一的bug是bug260.go,上面提到的,截至2010-05-04发布。
保亭

相关问题