Go 中的 Sizeof 结构体

问题描述 投票:0回答:6

我正在研究 Go,它看起来很有前途。 我试图弄清楚如何获取 go 结构的大小,例如 例如

type Coord3d struct {
    X, Y, Z int64
}

我当然知道它是 24 字节,但我想以编程方式知道它..

你有什么想法如何做到这一点吗?

struct go sizeof
6个回答
54
投票

Roger 已经展示了如何使用 unsafe 包中的 Sizeof 方法。请确保在依赖函数返回的值之前阅读此内容:

该大小不包括 x 可能引用的任何内存。为了 例如,如果 x 是切片,则 Sizeof 返回切片的大小 描述符,而不是切片引用的内存大小。

除此之外,我想解释如何使用几个简单的规则轻松计算任何结构的大小。然后如何使用有用的服务来验证你的直觉。


大小取决于它包含的类型以及结构中字段的顺序(因为将使用不同的填充)。这意味着具有相同字段的两个结构可以具有不同的大小。

例如,该结构体的 大小为 32

struct {
    a bool
    b string
    c bool
}

稍微修改一下,大小将为 24(由于字段排序更紧凑,所以存在 25%差异)

struct {
    a bool
    c bool
    b string
}

正如您从图片中看到的,在第二个示例中,我们删除了一个填充并移动了一个字段以利用之前的填充。对齐可以是 1、2、4 或 8。填充是用于填充变量以填充对齐的空间(基本上是浪费的空间)。

了解并记住这条规则:

  • bool、int8/uint8 占用 1 个字节
  • int16、uint16 - 2 字节
  • int32、uint32、float32 - 4 字节
  • int64、uint64、float64、指针 - 8 个字节
  • 字符串 - 16 字节(2 个 8 字节对齐)
  • 任何切片占用 24 个字节(3 个 8 字节对齐)。所以
    []bool
    [][][]string
    是相同的(不要忘记重读我在开头添加的引文)
  • 长度为
    n
    的数组需要
    n
    * 类型需要字节。

掌握了填充、对齐和字节大小的知识,您可以快速弄清楚如何改进您的结构(但使用服务验证您的直觉仍然有意义)。


47
投票
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。请参阅下面的评论。


10
投票

binary.TotalSize 也是一个选项,但请注意,它与 unsafe.Sizeof 之间的行为略有不同:binary.TotalSize 包括切片内容的大小,而 unsafe.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)
}

1
投票

这可能会发生变化,但最后我发现有一个与结构对齐相关的突出编译器错误(bug260.go)。最终结果是打包结构可能不会给出预期的结果。这是针对编译器 6g 版本 5383 发布的。2010-04-27 发布。它可能不会影响您的结果,但需要注意。

更新:Go 测试套件中剩下的唯一错误是 bug260.go,如上所述,截至 2010-05-04 发布。

布袋


0
投票

为了不产生初始化结构的开销,使用指向 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))
}

0
投票
/*
    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
}
© www.soinside.com 2019 - 2024. All rights reserved.