web-dev-qa-db-ja.com

Goの構造体のサイズ

私は非常に有望に見える囲碁を見ています。たとえば、go構造体のサイズを取得する方法を理解しようとしています。

type Coord3d struct {
    X, Y, Z int64
}

もちろん24バイトであることは知っていますが、プログラムで知りたいのですが。

これを行う方法について何かアイデアはありますか?

21
Jörg Haubrichs
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を返します。以下のコメントを参照してください。

34
RogerV

Rogerは、 nsafe パッケージの SizeOf メソッドの使用方法をすでに示しています。関数によって返される値に依存する前に、これを必ず読んでください。

サイズには、xによって参照される可能性のあるメモリは含まれていません。たとえば、xがスライスの場合、Sizeofは、スライスによって参照されるメモリのサイズではなく、スライス記述子のサイズを返します。

これに加えて、いくつかの簡単なルールを使用して、構造体のサイズを簡単に計算する方法を説明したいと思いました。そして、役立つ service を使用して直感を検証する方法。


サイズは、構成するタイプと構造体のフィールドの順序によって異なります(異なるパディングが使用されるため)。これは、同じフィールドを持つ2つの構造体のサイズが異なる可能性があることを意味します。

たとえば、この構造体のサイズは32になります

struct {
    a bool
    b string
    c bool
}

わずかな変更では、サイズが24(a25%フィールドのよりコンパクトな順序による違い)

struct {
    a bool
    c bool
    b string
}

enter image description hereenter image description here

写真からわかるように、2番目の例では、パディングの1つを削除し、前のパディングを利用するためにフィールドを移動しました。配置は、1、2、4、または8にすることができます。パディングは、配置を埋めるために変数を埋めるために使用されたスペースです(基本的に無駄なスペース)。

このルールを知り、それを覚えている:

  • bool、int8/uint8は1バイトを取ります
  • int16、uint16-2バイト
  • int32、uint32、float32-4バイト
  • int64、uint64、float64、pointer-8バイト
  • 文字列-16バイト(8バイトの2つの配置)
  • どのスライスも24バイトかかります(8バイトの3つの配置)。そう []bool[][][]stringは同じです(最初に追加した引用を読み直すことを忘れないでください)
  • 長さnの配列はn *バイトの型を取ります。

パディング、配置、バイト単位のサイズの知識があれば、構造体を改善する方法をすばやく理解できます(ただし、 サービスを使用して直感を確認する )。

31
Salvador Dali

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)
}
6
Evan Shaw

これは変更される可能性がありますが、最後に調べたところ、構造アラインメントに関連する未解決のコンパイラバグ(bug260.go)があります。最終的な結果として、構造体をパックしても期待した結果が得られない可能性があります。これは、コンパイラ6gバージョン5383release.2010-04-27リリース用でした。結果に影響を与えていない可能性がありますが、注意が必要です。

更新:リリース2010-05-04の時点で、goテストスイートに残っている唯一のバグは、上記のbug260.goです。

布袋

1
Hotei

構造体の初期化のオーバーヘッドが発生しないようにするには、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))
}
1
tst

binary パッケージを参照してください。具体的には、TotalSizeメソッド

0
marketer