Obecnie pracuję z pamięcią współdzieloną.
Nie rozumiem alignof
i alignas
.
cppreference jest niejasne: alignof
zwraca „wyrównanie”, ale co to jest „wyrównanie”? liczba bajtów do dodania dla następnego bloku do wyrównania? wyściełany rozmiar? Przepełnienie stosu / wpisy na blogach również są niejasne.
Czy ktoś może wyjaśnić jasno alignof
i alignas
?
c++
c++11
x86-64
memory-alignment
Offirmo
źródło
źródło
alignof
stronie (to robi teraz, na work-in-progress strony obiektu ). Nie wiem, jakie znaczenie ma strona cplusplus.com.Odpowiedzi:
Wyrównanie jest ograniczeniem, na którym można zapisać pierwszy bajt wartości w pamięci. (Konieczne jest poprawienie wydajności procesorów i zezwolenie na użycie niektórych instrukcji, które działają tylko na danych z określonym wyrównaniem, na przykład SSE musi być wyrównane do 16 bajtów, a AVX do 32 bajtów).
Wyrównanie 16 oznacza, że adresy pamięci będące wielokrotnością 16 są jedynymi prawidłowymi adresami.
alignas
wymuś wyrównanie do wymaganej liczby bajtów. Możesz wyrównać tylko do potęg 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); }
przykładowe dane wyjściowe:
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
drugie słowo kluczowe
alignof
jest bardzo wygodny, nie możesz zrobić czegoś takiego
int a[4]; assert(a % 16 == 0); // check if alignment is to 16 bytes: WRONG compiler error
ale możesz to zrobić
assert(alignof(a) == 16); assert(alignof(b) == 1024);
zauważ, że w rzeczywistości jest to bardziej rygorystyczne niż prosta operacja „%” (moduł). W rzeczywistości wiemy, że coś wyrównanego do 1024 bajtów jest koniecznie wyrównane do 1, 2, 4, 8 bajtów, ale
assert(alignof(b) == 32); // fail.
Aby być bardziej precyzyjnym, „alignof” zwraca największą potęgę 2 do tego, co jest wyrównane.
Również alignof jest dobrym sposobem, aby z góry poznać minimalne wymagania dotyczące dopasowania dla podstawowych typów danych (prawdopodobnie zwróci 1 dla znaków, 4 dla typu float itp.).
Nadal legalne:
alignas(alignof(float)) float SqDistance;
Coś z wyrównaniem 16 zostanie następnie umieszczone na następnym dostępnym adresie, który jest wielokrotnością 16 (może być niejawne wypełnienie od ostatnio używanego adresu).
źródło
sizeof
,alignof
można zastosować tylko do plikutype-id
.alignof()
(i odpowiednikalignas()
) oceniany w czasie kompilacji, więc nie ma narzutu w czasie wykonywania?alignof
to stała czasu kompilacji.alignas
nie jest i będzie musiał być obsługiwany przez Twoją implementacjęnew
(wymaganie standardu) lub przez niestandardowy alokator std .struct
i członków struktury, która jeststatic
.alignas
okazuje się znacznie bardziej wybredny niż__attribute__((aligned))
, szczególnie w przypadku kompilatorów takich jak Clang.Wyrównanie nie jest wypełnieniem (chociaż czasami wprowadzane jest wypełnienie, aby spełnić wymagania dotyczące wyrównania). Jest to wewnętrzna właściwość typu C ++. Aby umieścić to w standardese (
3.11[basic.align]
)źródło
struct X { char a; char b}
ma rozmiar 2 i wymóg wyrównania 1, w rozsądnych systemach (może być przydzielony pod dowolnym adresem, ponieważ znak można przypisać pod dowolnym adresem)alignof(std::max_align_t)
, co jest16
na moim Linuksie (niezależnie od tego, czy kompiluję -m32 czy -m64), ale możesz zwiększyć to za pomocąalignas
Każdy typ ma wymagania dotyczące wyrównania. Ogólnie rzecz biorąc, jest to tak, aby dostęp do zmiennych tego typu był efektywny, bez konieczności powodowania, że CPU generuje więcej niż jeden dostęp do odczytu / zapisu, aby dotrzeć do dowolnego elementu typu danych. Ponadto zapewnia również sprawne kopiowanie całej zmiennej.
alignof
zwróci wymagania dotyczące wyrównania dla danego typu.alignas
jest używany do wymuszania wyrównania dla typu danych (o ile nie jest mniej rygorystyczny, niżalignof
zwracany przez ten typ danych)źródło
Wyrównanie to właściwość związana z adresem pamięci. Po prostu możemy powiedzieć, że jeśli adres X jest wyrównany do Z, to x jest wielokrotnością Z, czyli X = Zn + 0. Tutaj ważne jest to, że Z jest zawsze potęgą 2.
Powyższą instrukcję można znaleźć w odwołaniu do Microsoft C ++.
Jeżeli element danych jest przechowywany w pamięci z adresem, który jest wyrównany do jego rozmiaru, wówczas mówi się, że element danych jest wyrównany naturalnie , w przeciwnym razie źle wyrównany. Na przykład: jeśli zmienna całkowita o rozmiarze 4 bajtów jest przechowywana pod adresem, który jest wyrównany do 4, to możemy powiedzieć, że zmienna jest wyrównana naturalnie, czyli adres zmiennej powinien być wielokrotnością 4.
Kompilatory zawsze starają się unikać niedopasowań. W przypadku prostych typów danych adresy są wybierane tak, aby stanowiły wielokrotność rozmiaru zmiennej w bajtach. Kompilator również odpowiednio wypełnia w przypadku struktur w celu naturalnego wyrównania i dostępu. Tutaj struktura zostanie wyrównana do maksymalnych rozmiarów różnych elementów danych w strukturze. Np .:
struct abc { int a; char b; };
Tutaj struktura abc jest wyrównana do 4, co jest rozmiarem elementu int, który jest oczywiście większy niż 1 bajt (rozmiar elementu char).
alignas
Ten specyfikator służy do wyrównania typów zdefiniowanych przez użytkownika, takich jak struktura, klasa itp., Do określonej wartości, która jest potęgą 2.
alignof
Jest to rodzaj operatora służącego do uzyskiwania wartości, do której jest wyrównana struktura lub typ klasy. na przykład:
#include <iostream> struct alignas(16) Bar { int i; // 4 bytes int n; // 4 bytes short s; // 2 bytes }; int main() { std::cout << alignof(Bar) << std::endl; // output: 16 }
źródło