Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Um dos recursos de baixo nível do C++ é a capacidade de especificar o alinhamento preciso de objetos na memória para tirar o máximo proveito de uma arquitetura de hardware específica. Por padrão, o compilador alinha os membros de classe e struct em seu valor de tamanho: bool e em limites de 1 byte, short em limites de 2 bytes, int, long, e float em limites de 4 bytes, e long long, doublee long double em limites de 8 byteschar.
Na maioria dos cenários, você nunca precisa se preocupar com o alinhamento porque o alinhamento padrão já é o ideal. Em alguns casos, no entanto, você pode obter melhorias significativas de desempenho ou economia de memória especificando um alinhamento personalizado para suas estruturas de dados. Antes do Visual Studio 2015, você podia usar as palavras-chave __alignof específicas da Microsoft e __declspec(align) especificar um alinhamento maior do que o padrão. A partir do Visual Studio 2015, você deve usar as palavras-chave alignof padrão C++11 e alignas para portabilidade máxima de código. As novas palavras-chave se comportam da mesma forma sob o capô que as extensões específicas da Microsoft. A documentação para essas extensões também se aplica às novas palavras-chave. Para obter mais informações, consulte alignof Operador, alignas especificador e alinhar. O padrão C++ não especifica o comportamento de empacotamento para alinhamento em limites menores do que o padrão do compilador para a plataforma de destino, portanto, você ainda precisa usar a Microsoft #pragma pack nesse caso.
Use a classe aligned_storage para alocação de memória de estruturas de dados com alinhamentos personalizados. A classe aligned_union é para especificar o alinhamento para uniões com construtores ou destruidores não triviais.
Alinhamento e endereços de memória
Alinhamento é uma propriedade de um endereço de memória, expressa como o módulo de endereço numérico uma potência de 2. Por exemplo, o endereço 0x0001103F módulo 4 é 3. Diz-se que esse endereço está alinhado com 4n+3, onde 4 indica a potência escolhida de 2. O alinhamento de um endereço depende do poder escolhido de 2. O mesmo endereço modulo 8 é 7. Diz-se que um endereço está alinhado a X se o seu alinhamento for Xn+0.
As CPUs executam instruções que operam em dados armazenados na memória. Os dados são identificados pelos seus endereços na memória. Um único dado também tem um tamanho. Chamamos um dado naturalmente alinhado se seu endereço estiver alinhado ao seu tamanho. Chama-se desalinhado de outra forma. Por exemplo, um dado de ponto flutuante de 8 bytes é naturalmente alinhado se o endereço usado para identificá-lo tiver um alinhamento de 8 bytes.
Tratamento do compilador do alinhamento de dados
Os compiladores tentam fazer alocações de dados de uma forma que evite o desalinhamento de dados.
Para tipos de dados simples, o compilador atribui endereços que são múltiplos do tamanho em bytes do tipo de dados. Por exemplo, o compilador atribui endereços a variáveis do tipo long que são múltiplos de 4, definindo os 2 bits inferiores do endereço como zero.
O compilador também preenche estruturas de uma forma que alinha naturalmente cada elemento da estrutura. Considere a estrutura struct x_ no exemplo de código a seguir:
struct x_
{
char a; // 1 byte
int b; // 4 bytes
short c; // 2 bytes
char d; // 1 byte
} bar[3];
O compilador preenche essa estrutura para impor o alinhamento naturalmente.
O exemplo de código a seguir mostra como o compilador coloca a estrutura acolchoada na memória:
// Shows the actual memory layout
struct x_
{
char a; // 1 byte
char _pad0[3]; // padding to put 'b' on 4-byte boundary
int b; // 4 bytes
short c; // 2 bytes
char d; // 1 byte
char _pad1[1]; // padding to make sizeof(x_) multiple of 4
} bar[3];
Ambas as declarações retornam sizeof(struct x_) como 12 bytes.
A segunda declaração inclui dois elementos de acolchoamento:
-
char _pad0[3]para alinhar oint bmembro em um limite de 4 bytes. -
char _pad1[1]para alinhar os elementos de matriz da estruturastruct _x bar[3];em um limite de 4 bytes.
O acolchoamento alinha os elementos de bar[3] uma forma que permite o acesso natural.
O exemplo de código a seguir mostra o layout da bar[3] matriz:
adr offset element
------ -------
0x0000 char a; // bar[0]
0x0001 char pad0[3];
0x0004 int b;
0x0008 short c;
0x000a char d;
0x000b char _pad1[1];
0x000c char a; // bar[1]
0x000d char _pad0[3];
0x0010 int b;
0x0014 short c;
0x0016 char d;
0x0017 char _pad1[1];
0x0018 char a; // bar[2]
0x0019 char _pad0[3];
0x001c int b;
0x0020 short c;
0x0022 char d;
0x0023 char _pad1[1];
alignof e alignas
O alignas especificador é uma maneira portátil padrão de C++ para especificar o alinhamento personalizado de variáveis e tipos definidos pelo usuário. O alignof operador é igualmente uma forma padrão e portátil de obter o alinhamento de um tipo ou variável especificados.
Exemplo
Você pode usar alignas em uma classe, struct ou sindicato, ou em membros individuais. Quando vários alignas especificadores são encontrados, o compilador escolhe aquele com o maior valor.
// alignas_alignof.cpp
// compile with: cl /EHsc alignas_alignof.cpp
#include <iostream>
struct alignas(16) Bar
{
int i; // 4 bytes
int n; // 4 bytes
alignas(4) char arr[3];
short s; // 2 bytes
};
int main()
{
std::cout << alignof(Bar) << std::endl; // output: 16
}