2010-12-14 6 views
5

Linia kod jest wart tysiąca słów :) Oto mój problem:C++ wyrównanie pamięć pytanie

/* Platform specific 16-byte alignment macro switch. 
    On Visual C++ it would substitute __declspec(align(16)). 
    On GCC it substitutes __attribute__((aligned (16))). 
*/ 
#define ALIGN_16 ... 

struct ALIGN_16 A {...}; 

A* ptr = new A; 
A* ptr2 = new A[20]; 

assert(size_t(ptr) % 16 == 0); 

for (int i=0; i<20; ++i) 
    assert(size_t(ptr2+i) % 16 == 0); 

assert(sizeof(A) % 16 == 0); 

mogę się spodziewać, że wszystkie twierdzenia przejść na platformach z obsługą SSE? Dziękuję Ci.

EDYCJA. Częściowa odpowiedź. Zrobiłem test z VS2008, GCC i ICC. Kompilator MS wyrównał zarówno ptr i ptr2, ale GCC i ICC nie udało się wyrównać ptr2.

+0

Dlaczego tablicą 20 Tak jak? – John

+0

Po prostu z mojej głowy. Błąkałem się, jeśli każdy element tablicy jest wyrównany. – watson1180

+2

Elementy poprawnie przydzielonej macierzy są gwarantowane przez standard, aby być odpowiednio wyrównane dla danego typu. To wyrównanie jest jednak szczegółem implementacji i teoretycznie może być jednym bajtem (to jest wyrównaniem spakowanym). –

Odpowiedz

4

Is there any guarantee of alignment of address return by C++'s new operation?

Innymi słowy, można użyć standardowego, aby uzasadnić swoje założenie, że to powinno działać, ale w praktyce może wysadzić w twarz.

Program Visual C++ 6 nie ustawił odpowiednio doubles za pośrednictwem new, więc możesz już iść.

+0

Co z nowszymi kompilatorami? GCC 4.xx i VS 2008? – watson1180

+1

Nie znam żadnych kompilatorów, które zapewniają wyrównanie 16 bajtów z 'new' lub' malloc', co oznacza, że ​​w praktyce nie uda się uzyskać potwierdzenia. – jalf

+0

@Jajf, tak, właśnie to wymyśliłem. Przypuszczam, że jest "obsługiwany" z C++ 0x, ale biorąc pod uwagę, że HeapAlloc gwarantuje pośrednio 8 bajtów (ponieważ domyślna opcja pakowania jest 8-bajtowym wyrównaniem dla struktur danych Windows), wątpię, aby to się stało w najbliższym czasie. – MSN

1

C++ 0x dostarcza nową konstrukcję (w [meta.type.synop]20.7.6.6 innych przekształceń):

std::aligned_storage<Length, Alignment> 

którym zagwarantowane jest zawsze prawidłowo wyrównane ile Oddzwonię.

Drugi parametr jest opcjonalny, a domyślny jest najostrzejszy możliwy warunek (tak, że zawsze można go bezpiecznie nie sprecyzować, ale możesz spakować swoje typy bardziej zwięźle, jeśli chcesz spróbować).

Oprócz bugs, kompilator jest zobowiązany spełnić to wymaganie. Jeśli nie masz C++ 0x, można go znaleźć w przestrzeni nazw tr1 lub Boost.

Jesteś jedyną osobą, która może sprawdzić, czy szczególności kompilator ma uhonorować tę prośbę :)

Uwaga: na gcc-4.3.2, jest zaimplementowany jako:

template<std::size_t _Len, std::size_t _Align = /**/> 
struct aligned_storage 
{ 
    union type 
    { 
    unsigned char __data[_Len]; 
    struct __attribute__((__aligned__((_Align)))) { } __align; 
    }; 
}; 
+0

Obiekty są przydzielane za pomocą 'new', co (zwykle) nie spełnia określonych wymagań dotyczących wyrównania. (Zwykle daje to 8-bajtową pamięć wyrównaną, która jest wystarczająco dobra dla większości celów). – jalf

+0

@jalf: ale standardowe polecenie, że 'new' zwraca odpowiednio wyrównany fragment pamięci (z 3.7.4.1 [basic.std.dynamic .allocation] $ 2), chyba że nie rozumiem *, aby można było go przekonwertować na wskaźnik dowolnego typu obiektu z podstawowym wymogiem wyrównania (3.11) * i od 3.11 [podstawowy.wyrównanie] 2 $ * Zasadnicze wyrównanie jest reprezentowane przez wyrównanie mniejsze lub równe największemu wyrównaniu wspieranemu przez implementację we wszystkich kontekstach, co jest równe alignof (std :: max_align_t) (18.2). * –

+0

... Dlatego powiedziałbym, że jeśli 'new' zwraca tylko 8 bajtowe wartości wyrównane, a' std :: max_align_t' ma wartość wyższą niż 8, to implementacja nie jest zgodna. –