Размер структуры в Go

Я смотрю на Go, который выглядит довольно многообещающим. Я пытаюсь выяснить, как получить размер структуры go, для например что-то вроде

type Coord3d struct {
    X, Y, Z int64
}

Конечно, я знаю, что это 24 байта, но я хотел бы знать это программно..

Есть ли у вас идеи, как это сделать?

Ответы

Ответ 1

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

ПРИМЕЧАНИЕ: ОП ошибочно. Небезопасный .Sizeof возвращает 24 на примере структуры Coord3d. См. Комментарий ниже.

Ответ 2

Роджер уже показал, как использовать метод SizeOf из пакета unsafe. Убедитесь, что вы прочитали это, прежде чем полагаться на значение, возвращаемое функцией:

Размер не содержит памяти, на которую может ссылаться x. Для instance, если 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 chunks
  • int32, uint32, float32 - 4 куска
  • int64, uint64, float64, указатель - 8 кусков Строка
  • - 16 кусков (2 выравнивания по 8 кусков)
  • любой фрагмент занимает 24 куска (3 выравнивания по 8 кусков). Итак, []bool, [][][]string одинаковы (не забудьте перечитать цитату, которую я добавил в начале)
  • массив длины n принимает n * тип, который требуется для кусков.

Вооружившись знаниями дополнений, выравнивания и фрагментов, вы можете быстро выяснить, как улучшить свою структуру (но все же имеет смысл проверить свою интуицию с помощью службы).

Ответ 3

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

Ответ 4

Смотрите пакет binary. В частности, метод TotalSize

Ответ 5

Это может быть изменено, но в последний раз, когда я смотрел, есть замечательная ошибка компилятора (bug260.go), связанная с выравниванием структуры. Конечным результатом является то, что упаковка структуры может не дать ожидаемых результатов. Это было для выпуска компилятора версии 699 версии 5383.2010-04-27. Это может не повлиять на ваши результаты, но это то, о чем нужно знать.

ОБНОВЛЕНИЕ. Единственная ошибка, оставленная в тестовом наборе go, - bug260.go, упомянутый выше, начиная с версии 2010-05-04.

Хотей

Ответ 6

Чтобы не нанести накладные расходы на инициализацию структуры, было бы быстрее использовать указатель на 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))
}