Размер структуры в 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))
}