2010-01-21 13 views
15

Echo un vistazo a Go, que parece bastante prometedor. estoy tratando de encontrar la manera de obtener el tamaño de una estructura ir, por ejemplo, algo así como Sizeof struct in Go

type Coord3d struct { 
    X, Y, Z int64 
} 

Por supuesto que sé que es 24 bytes, pero me gustaría saber mediante programación ..

¿Tiene alguna idea de cómo hacer esto?

Respuesta

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

NOTA: La OP es errónea. El inseguro. Sizeof devuelve 24 en la estructura ejemplo de Coord3d. Ver el comentario a continuación.

+1

El OP dijo específicamente "Intenté' inseguro.Sizeof' y no funcionó ". –

+0

si no se trabaja con 64 bittsts, entonces se debe alojar como un error. El uso de .saf no seguro aparece en muchos lugares en el código de la biblioteca Go y tiene la intención de ser una forma canónica de hacerlo, especialmente cuando se hace interfaz con bibliotecas C y llamadas a la API del sistema operativo. En cualquier caso, ciertamente funciona correctamente en el código que he escrito al usarlo. – RogerV

+1

Así que lo comprobé con el código que se muestra a continuación. El OP estaba equivocado. El inseguro. Sizeof devuelve correctamente 24 para su estructura de datos de ejemplo. (Mi compilador de Go se actualiza primera semana de enero de 2010.) paquete principal de importación ( insegura "inseguro" FMT "FMT" ) tipo Coord3d struct {X, Y, Z} Int64 func principal() { var pt Coord3d; const size = insafe.Sizeof (pt); fmt.Printf ("Tamaño de Coord3d:% d \ n", tamaño) } – RogerV

0

Consulte el paquete binary. Específicamente la TotalSize método

+0

¿Puede mostrar cómo usarlo de la manera correcta? Lo he probado varias veces y realmente no entiendo cómo obtener el material de reflexión para trabajar .. –

+0

En la versión actual de Go (1.1.2), esto es binary.Size() –

+0

Y no hace lo que el PO pregunta. –

6

binary.TotalSize también es una opción, pero tenga en cuenta que hay una ligera diferencia en el comportamiento entre eso y inseguro.Sizeof: binary.TotalSize incluye el tamaño del contenido de las rodajas, mientras que inseguro.Sizeof solo devuelve el tamaño de la parte superior descriptor de nivel. Aquí hay un ejemplo de cómo usar 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) 
} 
+0

NewValue se renombra a ValueOf en Go release.r60.3 –

+0

'binary.Size' es [completamente diferente] (https://play.golang.org/p/5qPsFRmFKI) de' unsafe.Sizeof' y existe para un razón completamente diferente. No es para nada lo que pidió el OP. –

+0

la función binary.TotalSize ya no está disponible en go. Creo que el código debería ser: 'var t T; s: = binary.Size (t); fmt.Println (s) ' – Komu

0

Esto está sujeta a cambios, pero la última que se veía hay un error de compilador destacado (bug260.go) relacionados con estructura de alineación. El resultado final es que empaquetar una estructura puede no dar los resultados esperados. Eso fue para el compilador 6g versión 5383 versión.2010-04-27. Puede no estar afectando sus resultados, pero es algo de lo que debe estar consciente.

ACTUALIZACIÓN: El único error que queda en el conjunto de pruebas go es bug260.go, mencionado anteriormente, a partir del lanzamiento 2010-05-04.

Hotei

+0

Creo que te estás refiriendo a [issue/482] (https://github.com/golang/go/issues/482) que se cerró en diciembre de 2010. Dado que eso era mucho antes de Go1 .0 ¿debería existir esta "respuesta"? –

0

Con el fin de no incurrir en los gastos generales de la inicialización de una estructura, sería más rápido utilizar un puntero a 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

Si va a confiar en la eliminación de referencia de un puntero nulo (que solo funciona aquí debido a un detalle de implementación de la implementación * actual * 'insegura.Sizeof', dudo que sea un código legal), también podría [ eliminar cualquier variable en absoluto] (https://play.golang.org/p/_6u_l0OQkB). –

14

Roger ya mostraba cómo utilizar SizeOf método de la unsafe paquete. Asegúrese de leer esto antes de confiar en el valor devuelto por la función:

El tamaño no incluye ninguna memoria referenciada posiblemente por x. Para la instancia , si x es un sector, Sizeof devuelve el tamaño del descriptor de segmento , no el tamaño de la memoria a la que hace referencia el segmento.

Además de esto quería explicar cómo se puede calcular fácilmente el tamaño de cualquier estructura utilizando un par de reglas simples. Y luego, cómo verificar tu intuición usando un útil service.


El tamaño depende de los tipos que la componen y el orden de los campos en la estructura (porque se utilizará diferente relleno). Esto significa que dos estructuras con los mismos campos pueden tener diferentes tamaños.

Por ejemplo este struct tendrá un tamaño de 32

struct { 
    a bool 
    b string 
    c bool 
} 

y una ligera modificación tendrá un tamaño de 24 (una diferencia 25% simplemente debido a un ordenamiento más compacta de campos)

struct { 
    a bool 
    c bool 
    b string 
} 

enter image description hereenter image description here

Como se puede ver en las imágenes, en el segundo ejemplo hemos eliminado uno de los rellenos y se trasladó un campo para aprovechar el relleno anterior. Una alineación puede ser 1, 2, 4 u 8. Un relleno es el espacio que se usó para completar la variable para llenar la alineación (básicamente espacio desperdiciado).

Sabiendo esta regla y recordando que:

  • bool, INT8/uint8 tomar 1 trozo
  • Int16, uint16 - 2 trozos
  • int32, uint32, Float32 - 4 trozos
  • Int64, uint64, float64, puntero - 8 trozos
  • cadena - 16 trozos (2 alineaciones de 8 trozos)
  • cualquier rebanada toma 24 trozos (3 alineaciones de 8 trozos). Entonces []bool, [][][]string son lo mismo (no olvide volver a leer la cita que agregué al principio)
  • matriz de longitud n toma n * tipo de toma de fragmentos.

Armado con el conocimiento de relleno, alineación y trozos se puede averiguar rápidamente cómo mejorar su estructura (pero todavía tiene sentido verify your intuition using the service).

+0

Es correcto. Puedo ver el tamaño de la diferencia. {bool, int8} es 2, {bool, int16} es 4, {bool, int32} es 8. – firelyu