2010-01-21 14 views
15

Sto dando un'occhiata a Go, che sembra abbastanza promettente. sto cercando di capire come ottenere le dimensioni di una struct andare, per esempio, qualcosa come Sizeof struct in Go

type Coord3d struct { 
    X, Y, Z int64 
} 

Naturalmente so che si tratta di 24 byte, ma mi piacerebbe sapere a livello di codice ..

Avete qualche idea su come fare questo?

risposta

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: L'OP si sbaglia. Il non sicuro. Sizeof restituisce 24 sulla struttura di Coord3d esempio. Vedi il commento qui sotto.

+1

L'OP ha detto in particolare "Ho provato' unssafe.Sizeof' e non ha funzionato. " –

+0

se non funziona con 64 bit inte deve essere inserito come bug. L'uso di non sicuro.Sizeof appare in molti punti nel codice della libreria Go ed è inteso come un modo cannoical per fare ciò, specialmente quando si interfaccia alle librerie C e alle chiamate dell'OS del sistema operativo. Ad ogni modo, sicuramente funziona correttamente nel codice che ho scritto usando. – RogerV

+1

Quindi ho controllato con il codice mostrato di seguito. Il PO era sbagliato. Il non sicuro. Sizeof restituisce correttamente 24 per la sua struttura di dati di esempio. (Il mio compilatore Go è stato aggiornato prima settimana di gennaio 2010.) pacchetto principale importazione ( non sicuro "non sicuro" fmt "fmt" ) tipo Coord3d struct {X, Y, Z Int64} func principale() { var pt Coord3d; const size = unsafe.Sizeof (pt); fmt.Printf ("Size of Coord3d:% d \ n", size) } – RogerV

0

Vedere il pacchetto binary. Specificamente il TotalSize metodo

+0

Puoi mostrare come usarlo nel modo giusto? L'ho provato più volte e non ho davvero capito come far funzionare la riflessione. –

+0

Nella versione corrente di Go (1.1.2), questo è binary. Dimensione() –

+0

E non fa ciò che l'OP chiede. –

6

binary.TotalSize è anche un'opzione, ma nota che c'è una leggera differenza di comportamento tra questo e unsafe.Sizeof: binary.TotalSize include la dimensione del contenuto di slice, mentre non sicuro.Sizeof restituisce solo la dimensione della parte superiore descrittore di livello. Ecco un esempio di come utilizzare 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

il NewValue viene rinominato in ValueOf in Go release.r60.3 –

+0

'binary.Size' è [completamente diverso] (https://play.golang.org/p/5qPsFRmFKI) da' unsafe.Sizeof' ed esiste per un motivo completamente diverso. Non è affatto ciò che l'OP chiedeva. –

+0

la funzione binary.TotalSize non è più disponibile in go. Penso che il codice dovrebbe essere: 'var t T; s: = binary.Size (t); fmt.Println (s) ' – Komu

0

Questo è soggetto a modifiche, ma ultima volta che ho guardato c'è un eccezionale bug del compilatore (bug260.go) relativi a struttura di allineamento. Il risultato finale è che l'imballaggio di una struttura potrebbe non dare i risultati attesi. Quello era per il compilatore 6g versione 5383 release.2010-04-27. Potrebbe non influire sui risultati, ma è qualcosa di cui essere a conoscenza.

AGGIORNAMENTO: l'unico bug rimasto nella suite di test di go è bug260.go, menzionato sopra, a partire dalla versione 2010-05-04.

Hotei

+0

Credo che tu ti stia riferendo a [issue/482] (https://github.com/golang/go/issues/482) che è stato chiuso a dicembre 2010. Dato che era molto prima di Go1 .0 questa "risposta" esiste ancora? –

0

Per non incorrere l'overhead di inizializzare una struttura, sarebbe più veloce di utilizzare un puntatore 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

Se hai intenzione di fare affidamento sulla de-referenziazione di un puntatore nil (che funziona solo qui a causa dell'implementazione dell'implementazione * current * 'unssafe.Sizeof', dubito che questo sia un codice legale), potresti anche [ eliminare qualsiasi variabile a tutti] (https://play.golang.org/p/_6u_l0OQkB). –

14

Roger già mostrato come utilizzare SizeOf metodo dal unsafe pacchetto. Assicurati di leggere questo prima di fare affidamento sul valore restituito dalla funzione:

La dimensione non include alcuna memoria eventualmente indicata da x. Per l'istanza , se x è una sezione, Sizeof restituisce la dimensione del descrittore della porzione , non la dimensione della memoria a cui fa riferimento la porzione.

In aggiunta a questo ho voluto spiegare come è possibile calcolare facilmente le dimensioni di qualsiasi struttura utilizzando un paio di semplici regole. E poi come verificare il tuo intuito usando un utile service.


La dimensione dipende dai tipi che la compongono e l'ordine dei campi nella struct (perché sarà usato imbottitura diversa). Ciò significa che due strutture con gli stessi campi possono avere dimensioni diverse.

Ad esempio questo struct avrà una dimensione di 32

struct { 
    a bool 
    b string 
    c bool 
} 

e una lieve modifica avrà una dimensione di 24 (una differenza 25% solo a causa di un ordine più compatto campi)

struct { 
    a bool 
    c bool 
    b string 
} 

enter image description hereenter image description here

Come si vede dalle immagini, nel secondo esempio abbiamo rimosso uno dei paddings e spostato un campo per sfruttare il riempimento precedente. Un allineamento può essere 1, 2, 4 o 8. Un riempimento è lo spazio utilizzato per riempire la variabile per riempire l'allineamento (spazio sostanzialmente sprecato).

Conoscendo questa regola e ricordando che:

  • bool, int8/uint8 prendere 1 pezzo
  • Int16, UINT16 - 2 pezzi
  • Int32, Uint32, Float32 - 4 pezzi
  • Int64, uint64, float64, pointer - 8 blocchi
  • stringa - 16 blocchi (2 allineamenti di 8 blocchi)
  • qualsiasi sezione richiede 24 blocchi (3 allineamenti di 8 blocchi). Quindi []bool, [][][]string sono gli stessi (non dimenticare di rileggere la citazione che ho aggiunto all'inizio)
  • array di lunghezza n prende n * tipo che prende dei blocchi.

Armati con la conoscenza di imbottitura, allineamento e pezzi si può capire rapidamente come migliorare la vostra struct (ma ancora ha senso verify your intuition using the service).

+0

È corretto. Posso vedere la differenza di dimensione. {bool, int8} è 2, {bool, int16} è 4, {bool, int32} è 8. – firelyu