2013-06-13 10 views
36

Attualmente lavoro con la memoria condivisa.Allineamento memoria: come usare alignof/alignas?

Non riesco a capire alignof e alignas.

cppreference non è chiaro: alignof restituisce "allineamento" ma cos'è "allineamento"? numero di byte da aggiungere per il prossimo blocco da allineare? dimensione imbottita? Stack overflow/le voci dei blog non sono chiare.

Qualcuno può spiegare chiaramente alignof e alignas?

+1

cppreference sta cercando di essere un riferimento piuttosto che un tutorial – Cubbi

+0

@Cubbi: puoi anche controllare su cplusplus.com, c'è dibattito su quale sito è migliore, per certi argomenti cplusplus è migliore, per altri cppreference è meglio, ho trovato che entrambi i siti certe volte non ci sono eonugh – GameDeveloper

+1

@DarioOO Stavo solo rispondendo perché cppreference non spiega il concetto di allineamento sulla pagina 'alignof' (lo fa ora, sul work-in-progress [oggetto pagina] (http: //en.cppreference.com/w/cpp/language/object#Alignment)). Non vedo come cplusplus.com sia rilevante. – Cubbi

risposta

36

allineamento è una restrizione quale memoria posiziona primo byte di un valore può essere memorizzato . (È necessario migliorare le prestazioni sui processori e consentire l'uso di determinate istruzioni che funzionano solo su dati con allineamento particolare, ad esempio SSE deve essere allineato a 16 byte, mentre AVX a 32 byte.)

Allineamento di 16 significa che gli indirizzi di memoria multipli di 16 sono gli unici indirizzi validi. allineamento

alignas 

forza al numero di byte richiesto (cppreference non ne parla, ma penso che si può allineare solo potenze di 2: 1, 2, 4, 8, 16, 32, 64, 128,. ..)

#include <cstdlib> 
#include <iostream> 

int main() { 
    alignas(16) int a[4]; 
    alignas(1024) int b[4]; 
    printf("%p\n", a); 
    printf("%p", b); 
} 

output di esempio:

0xbfa493e0 
0xbfa49000 // note how many more "zeros" now. 
// binary equivalent 
1011 1111 1010 0100 1001 0011 1110 0000 
1011 1111 1010 0100 1001 0000 0000 0000 // every zero is just a extra power of 2 

l'altra parola chiave

alignof 

è molto conveniente, non si può fare qualcosa di simile

int a[4]; 
assert(a % 16 == 0); // check if alignment is to 16 bytes: WRONG compiler error 

ma si può fare

01.235.
assert(alignof(a) == 16); 
assert(alignof(b) == 1024); 

nota che in realtà questo è più rigido di una semplice operazione "%" (modulo). In realtà sappiamo che qualcosa allineato a 1024 byte è necessariamente allineata a 1, 2, 4, 8 byte ma

assert(alignof(b) == 32); // fail. 

Quindi, per essere più precisi, "alignof" restituisce il più grande potere di 2 a wich qualcosa è allineato .

Anche alignof è un buon modo per conoscere in anticipo il requisito di allineamento minimo per i tipi di dati di base (probabilmente restituirà 1 per char, 4 per float ecc.).

ancora legale:

alignas(alignof(float)) float SqDistance; 

Qualcosa con un allineamento di 16 poi sarà posto sul prossimo indirizzo disponibile che è un multiplo di 16 (ci può essere un imbottitura implicita da ultimo indirizzo utilizzato).

+6

A differenza di' sizeof', 'alignof' può essere applicato solo a un 'id-tipo'. – neverhoodboy

+0

è 'alignof()' (e la controparte 'alignas()') valutata al momento della compilazione, quindi nessun sovraccarico di runtime? – nonsensation

+0

no. Non è possibile, il compilatore può farlo come ottimizzazione in pochissimi casi, ma in generale non saprà come gli indirizzi di memoria sono allineati prima di valutare le 2 funzioni. Basta guardare l'assembly generato dal mio esempio: http://goo.gl/ZbemBF – GameDeveloper

5

L'allineamento non è il riempimento (sebbene l'imbottitura venga talvolta introdotta per soddisfare i requisiti di allineamento). È una proprietà intriseca di un tipo C++. Per dirla nello standard (3.11[basic.align])

tipi di oggetti hanno requisiti di allineamento (3.9.1, 3.9.2), che limitano gli indirizzi a cui possono essere assegnate un oggetto di quel tipo. Un allineamento è un valore intero definito dall'implementazione che rappresenta il numero di byte tra gli indirizzi successivi a cui può essere assegnato un dato oggetto. Un tipo di oggetto impone un requisito di allineamento su ogni oggetto di quel tipo; un allineamento più severo può essere richiesto usando lo specificatore di allineamento (7.6.2).

+1

Molto interessante. Ti dispiacerebbe dare qualche esempio? L'allineamento (struct X) == sizeof (struct X)? Perchè no ? – Offirmo

+1

@Offirmo no, tranne per concidenza: 'struct X {char a; char b} 'ha dimensione 2 e requisito di allineamento 1, su sistemi sensati (può essere assegnato a qualsiasi indirizzo perché un char può essere assegnato a qualsiasi indirizzo) – Cubbi

+0

req allineamento di 1 ???? Oh capisco: pensavo che l'allineamento fosse sempre su limiti "naturali" a 32 bit/64 bit, ma apparentemente no. Questo spiega le cose ... Quindi, con le solite macchine, il risultato di alignof() sarà sempre al massimo a 4 (32 bit) o ​​8 (64 bit). Ho ragione? – Offirmo

3

Ogni tipo ha un requisito di allineamento. In genere, è possibile accedere in modo efficiente a variabili di questo tipo, senza dover far sì che la CPU generi più di un accesso in lettura/scrittura per raggiungere qualsiasi membro del tipo di dati. Inoltre, garantisce anche una copia efficiente dell'intera variabile. alignof restituirà il requisito di allineamento per il tipo specificato.

alignas è usato per forzare un allineamento su un tipo di dati (purché non sia meno rigorosi che ciò alignof detta datatype ritornerebbe)