Go 中的结构体大小

发布于 2024-08-18 22:11:01 字数 173 浏览 11 评论 0原文

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

type Coord3d struct {
    X, Y, Z int64
}

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

您知道如何做到这一点吗?

I'm having a look at Go, which looks quite promising.
I am trying to figure out how to get the size of a go struct, for
example something like

type Coord3d struct {
    X, Y, Z int64
}

Of course I know that it's 24 bytes, but I'd like to know it programmatically..

Do you have any ideas how to do this ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

烟火散人牵绊 2024-08-25 22:11:01

Roger 已经展示了如何使用 Sizeof 方法golang.org/pkg/unsafe" rel="nofollow noreferrer">不安全 包。请确保在依赖函数返回的值之前阅读此内容:

该大小不包括 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 个字节
  • string - 16 个字节(2 个 8 字节对齐)
  • 任何切片占用 24 个字节(3 个 8 字节对齐)。所以 []bool[][][]string 是相同的(不要忘记重新阅读我在开头添加的引文)
  • 长度为 n 的数组 采用 n * 其采用字节的类型。

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

Roger already showed how to use Sizeof method from the unsafe package. Make sure you read this before relying on the value returned by the function:

The size does not include any memory possibly referenced by x. For
instance, if x is a slice, Sizeof returns the size of the slice
descriptor, not the size of the memory referenced by the slice.

In addition to this I wanted to explain how you can easily calculate the size of any struct using a couple of simple rules. And then how to verify your intuition using a helpful service.


The size depends on the types it consists of and the order of the fields in the struct (because different padding will be used). This means that two structs with the same fields can have different size.

For example this struct will have a size of 32

struct {
    a bool
    b string
    c bool
}

and a slight modification will have a size of 24 (a 25% difference just due to a more compact ordering of fields)

struct {
    a bool
    c bool
    b string
}

enter image description hereenter image description here

As you see from the pictures, in the second example we removed one of the paddings and moved a field to take advantage of the previous padding. An alignment can be 1, 2, 4, or 8. A padding is the space that was used to fill in the variable to fill the alignment (basically wasted space).

Knowing this rule and remembering that:

  • bool, int8/uint8 take 1 byte
  • int16, uint16 - 2 bytes
  • int32, uint32, float32 - 4 bytes
  • int64, uint64, float64, pointer - 8 bytes
  • string - 16 bytes (2 alignments of 8 bytes)
  • any slice takes 24 bytes (3 alignments of 8 bytes). So []bool, [][][]string are the same (do not forget to reread the citation I added in the beginning)
  • array of length n takes n * type it takes of bytes.

Armed with the knowledge of padding, alignment and sizes in bytes, you can quickly figure out how to improve your struct (but still it makes sense to verify your intuition using the service).

画尸师 2024-08-25 22:11:01
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。请参阅下面的评论。

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)
    ...
}

NOTE: The OP is mistaken. The unsafe.Sizeof does return 24 on the example Coord3d struct. See comment below.

与风相奔跑 2024-08-25 22:11:01

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)
}

binary.TotalSize is also an option, but note there's a slight difference in behavior between that and unsafe.Sizeof: binary.TotalSize includes the size of the contents of slices, while unsafe.Sizeof only returns the size of the top level descriptor. Here's an example of how to use 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)
}
等待我真够勒 2024-08-25 22:11:01

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

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

布袋

This is subject to change but last I looked there is an outstanding compiler bug (bug260.go) related to structure alignment. The end result is that packing a structure might not give the expected results. That was for compiler 6g version 5383 release.2010-04-27 release. It may not be affecting your results, but it's something to be aware of.

UPDATE: The only bug left in go test suite is bug260.go, mentioned above, as of release 2010-05-04.

Hotei

恋你朝朝暮暮 2024-08-25 22:11:01

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

In order to not to incur the overhead of initializing a structure, it would be faster to use a pointer to 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))
}
梦行七里 2024-08-25 22:11:01
/*
    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
}
/*
    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
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文