Sdílet prostřednictvím


align (C++)

V sadě Visual Studio 2015 a novější použijte alignas specifikátor (C++11) k řízení zarovnání. Další informace naleznete v tématu Zarovnání.

Specifické pro Microsoft

Umožňuje __declspec(align(#)) přesně řídit zarovnání uživatelem definovaných dat (například statické přidělení nebo automatická data ve funkci).

Syntaxe

__declspec( align(#) )deklarátor

Poznámky

Psaní aplikací, které používají nejnovější pokyny k procesoru, přináší některá nová omezení a problémy. Mnoho nových instrukcí vyžaduje, aby data byla zarovnaná na 16 bajtů. Sladění často používaných dat s velikostí čáry mezipaměti procesoru zlepšuje výkon mezipaměti. Pokud například definujete strukturu, jejíž velikost je menší než 32 bajtů, můžete chtít zarovnání 32 bajtů, abyste zajistili efektivní ukládání objektů tohoto typu struktury do mezipaměti.

# je hodnota zarovnání. Platné položky jsou celočíselné pravomoci dvou od 1 do 8192 (bajty), například 2, 4, 8, 16, 32 nebo 64. declarator je data, která deklarujete jako zarovnaná.

Informace o tom, jak vrátit hodnotu typu size_t , která je požadavek na zarovnání typu, naleznete v tématu alignof. Informace o tom, jak deklarovat nerovnané ukazatele při cílení na 64bitové procesory, naleznete v tématu __unaligned.

Můžete použít __declspec(align(#)) , když definujete proměnnou struct, unionnebo class, nebo když deklarujete proměnnou.

Kompilátor nezaručuje nebo se pokusí zachovat atribut zarovnání dat během operace kopírování nebo transformace dat. Můžete například memcpy zkopírovat strukturu deklarovanou s jakýmkoli umístěním __declspec(align(#)) . Běžné alokátory (například C malloc++ operator newa alokátory Win32) obvykle vrací paměť, která není zarovnaná pro __declspec(align(#)) struktury nebo pole struktur. Chcete-li zaručit, že cíl operace kopírování nebo transformace dat je správně zarovnaný, použijte _aligned_malloc. Nebo napište vlastní alokátor.

Pro parametry funkce nelze zadat zarovnání. Když předáte data, která mají atribut zarovnání podle hodnoty v zásobníku, volající konvence řídí jeho zarovnání. Pokud je zarovnání dat ve volané funkci důležité, před použitím zkopírujte parametr do správně zarovnané paměti.

Bez __declspec(align(#)), kompilátor obvykle zarovná data na přirozených hranicích na základě cílového procesoru a velikosti dat, až 4 bajtové hranice na 32bitových procesorech a 8 bajtových hranic na 64bitových procesorech. Data ve třídách nebo strukturách jsou zarovnaná do třídy nebo struktury minimálně podle přirozeného zarovnání a aktuálního nastavení balení (z #pragma pack nebo možnosti kompilátoru /Zp ).

Tento příklad ukazuje použití __declspec(align(#)):

__declspec(align(32)) struct Str1{
   int a, b, c, d, e;
};

Tento typ má nyní atribut zarovnání 32 bajtů. To znamená, že všechny statické a automatické instance začínají na hranici 32 bajtů. Jiné typy struktury deklarované s tímto typem jako člen zachová atribut zarovnání tohoto typu. To znamená, že jakákoli struktura s Str1 jako element má atribut zarovnání nejméně 32.

sizeof(struct Str1) Tady je rovno 32. To znamená, že pokud je vytvořena matice Str1 objektů a základ pole je zarovnán 32 bajtů, každý člen pole je také zarovnaný 32 bajtů. Chcete-li vytvořit pole, jehož základ je správně zarovnán v dynamické paměti, použijte _aligned_malloc. Nebo napište vlastní alokátor.

Hodnota sizeof pro libovolnou strukturu je posun konečného členu plus velikost daného členu zaokrouhlená nahoru na nejbližší násobek hodnoty zarovnání největšího členu nebo celé hodnoty zarovnání struktury podle toho, co je větší.

Kompilátor používá tato pravidla pro zarovnání struktury:

  • Pokud není přepsáno __declspec(align(#)), zarovnání skalární struktury člen je minimální jeho velikost a aktuální balení.

  • Pokud není přepsáno __declspec(align(#)), zarovnání struktury je maximální počet jednotlivých zarovnání jejích členů.

  • Člen struktury se umístí na odsazení od začátku nadřazené struktury, která je nejmenším násobkem zarovnání větší než nebo rovna posunu konce předchozího členu.

  • Velikost struktury je nejmenší násobek jeho zarovnání větší nebo roven posunu konce jeho posledního členu.

__declspec(align(#)) může zvýšit pouze omezení zarovnání.

Další informace naleznete v tématu:

align Příklady

Následující příklady ukazují, jak __declspec(align(#)) ovlivňuje velikost a zarovnání datových struktur. Příklady předpokládají následující definice:

#define CACHE_LINE  32
#define CACHE_ALIGN __declspec(align(CACHE_LINE))

V tomto příkladu S1 je struktura definována pomocí __declspec(align(32)). Všechna použití S1 pro definici proměnné nebo v jiných deklarací typu jsou zarovnaná na 32 bajtů. sizeof(struct S1) vrátí hodnotu 32 a S1 má 16 bajtů odsazení za 16 bajtů potřebných k uložení čtyř celých čísel. Každý int člen vyžaduje zarovnání 4 bajtů, ale zarovnání samotné struktury je deklarováno jako 32. Pak je celkové zarovnání 32.

struct CACHE_ALIGN S1 { // cache align all instances of S1
   int a, b, c, d;
};
struct S1 s1;   // s1 is 32-byte cache aligned

V tomto příkladu sizeof(struct S2) vrátí hodnotu 16, což je přesně součet velikostí členů, protože se jedná o násobek největšího požadavku na zarovnání (násobek 8).

__declspec(align(8)) struct S2 {
   int a, b, c, d;
};

V následujícím příkladu sizeof(struct S3) vrátí hodnotu 64.

struct S3 {
   struct S1 s1;   // S3 inherits cache alignment requirement
                  // from S1 declaration
   int a;         // a is now cache aligned because of s1
                  // 28 bytes of trailing padding
};

V tomto příkladu si všimněte, že a má zarovnání přirozeného typu, v tomto případě 4 bajty. Musí S1 však být zarovnaný na 32 bajtů. Následuje 28 bajtů odsazení a, takže s1 začíná odsazením 32. S4 pak zdědí požadavek S1na zarovnání , protože je to největší požadavek na zarovnání ve struktuře. sizeof(struct S4) vrátí hodnotu 64.

struct S4 {
   int a;
   // 28 bytes padding
   struct S1 s1;      // S4 inherits cache alignment requirement of S1
};

Následující tři deklarace proměnných také používají __declspec(align(#)). V každém případě musí být proměnná zarovnaná na 32 bajtů. V matici je základní adresa matice, nikoli každý člen pole, zarovnaná na 32 bajtů. Hodnota sizeof pro každý člen pole není ovlivněna při použití __declspec(align(#)).

CACHE_ALIGN int i;
CACHE_ALIGN int array[128];
CACHE_ALIGN struct s2 s;

Pokud chcete zarovnat každý člen pole, měl by se použít například kód:

typedef CACHE_ALIGN struct { int a; } S5;
S5 array[10];

V tomto příkladu si všimněte, že zarovnání samotné struktury a zarovnání prvního prvku má stejný účinek:

CACHE_ALIGN struct S6 {
   int a;
   int b;
};

struct S7 {
   CACHE_ALIGN int a;
               int b;
};

S6 a S7 mají stejné vlastnosti zarovnání, přidělování a velikosti.

V tomto příkladu je zarovnání počátečních aadres , b, ca d jsou 4, 1, 4 a 1 v uvedeném pořadí.

void fn() {
   int a;
   char b;
   long c;
   char d[10]
}

Zarovnání při přidělení paměti na haldě závisí na tom, která funkce přidělení je volána. Pokud například použijete malloc, výsledek závisí na velikosti operandu. Pokud arg>= 8, vrácená paměť je zarovnaná 8 bajtů. Pokud arg< 8, zarovnání vrácené paměti je první mocnina 2 menší než arg. Pokud například použijete malloc(7), zarovnání je 4 bajty.

Definování nových typů pomocí __declspec(align(#))

Typ můžete definovat s charakteristikou zarovnání.

Můžete například definovat struct hodnotu zarovnání tímto způsobem:

struct aType {int a; int b;};
typedef __declspec(align(32)) struct aType bType;

aType Teď a bType jsou stejné velikosti (8 bajtů), ale proměnné typu bType jsou zarovnané na 32 bajtů.

Zarovnání dat v místním úložišti vlákna

Statické úložiště TLS (Thread-Local Storage) vytvořené s atributem __declspec(thread) a vložení do oddílu TLS na obrázku funguje pro zarovnání přesně stejně jako normální statická data. Pokud chcete vytvořit data PROTOKOLU TLS, operační systém přiděluje paměť velikosti oddílu TLS a respektuje atribut zarovnání oddílu TLS.

Tento příklad ukazuje různé způsoby umístění zarovnaných dat do místního úložiště vlákna.

// put an aligned integer in TLS
__declspec(thread) __declspec(align(32)) int a;

// define an aligned structure and put a variable of the struct type
// into TLS
__declspec(thread) __declspec(align(32)) struct F1 { int a; int b; } a;

// create an aligned structure
struct CACHE_ALIGN S9 {
   int a;
   int b;
};
// put a variable of the structure type into TLS
__declspec(thread) struct S9 a;

Jak align funguje s balením dat

Možnost /Zp kompilátoru a direktiva pack pragma mají vliv na balení dat pro členy struktury a sjednocení. Tento příklad ukazuje, jak /Zp a __declspec(align(#)) jak spolupracovat:

struct S {
   char a;
   short b;
   double c;
   CACHE_ALIGN double d;
   char e;
   double f;
};

V následující tabulce je uveden posun každého člena pod různými /Zp (nebo #pragma pack) hodnotami, které znázorňují způsob interakce těchto dvou členů.

Proměnná /Zp1 /Zp2 /Zp4 /Zp8
d 0 0 0 0
b 1 2 2 2
c 3 4 4 8
d 32 32 32 32
e 40 40 40 40
f 41 42 44 48
sizeof(S) 64 64 64 64

Další informace naleznete v tématu /Zp (Zarovnání člena struktury).

Posun objektu je založen na posunu předchozího objektu a aktuálním nastavení balení, pokud objekt nemá __declspec(align(#)) atribut, v takovém případě je zarovnání založeno na posunu předchozího objektu a __declspec(align(#)) hodnotě objektu.

END Microsoft Specific

Viz také

__declspec
Přehled konvencí ARM ABI
x64 – softwarové konvence