Alinhamento (C11)

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 da arquitetura de hardware.

As CPUs leem e gravam memória com mais eficiência quando armazenam dados em um endereço que é um múltiplo do tamanho dos dados. Por exemplo, um inteiro de 4 bytes será acessado com mais eficiência se ele for armazenado em um endereço que seja um múltiplo de 4. Quando os dados não estão alinhados, a CPU trabalha mais para fazer os cálculos de endereço para acessar os dados.

Por padrão, o compilador alinha dados com base em seu tamanho: char em um limite de 1 byte, short em um limite de 2 bytes, int, long e float em um limite de 4 bytes, double no limite de 8 bytes e assim por diante.

Além disso, ao alinhar os dados usados com frequência com o tamanho da linha de cache do processador, você melhora o desempenho do cache. Por exemplo, digamos que você defina uma estrutura cujo tamanho seja menor que 32 bytes. Talvez você queira usar o alinhamento de 32 bytes para garantir que todas as instâncias da estrutura sejam armazenadas em cache com eficiência.

Normalmente, não é necessário se preocupar com alinhamento. O compilador geralmente alinha dados em limites naturais baseados no processador de destino e no tamanho dos dados. Os dados são alinhados em limites de até 4 bytes em processadores de 32 bits e limites de 8 bytes em processadores de 64 bits. Em alguns casos, no entanto, você pode obter melhorias de desempenho ou economia de memória, especificando um alinhamento personalizado para suas estruturas de dados.

Use a palavra-chave _Alignof C11 para obter o alinhamento preferencial de um tipo ou variável e _Alignas para especificar um alinhamento personalizado para um tipo definido pelo usuário ou variável.

As macros de conveniência alignof e alignas, definidas em <stdalign.h>, mapeiam diretamente para _Alignof e _Alignas, respectivamente. Essas macros correspondem às palavras-chave usadas no C++. Portanto, usar as macros em vez das palavras-chave C pode ser útil para portabilidade de código se você compartilhar qualquer código entre os dois idiomas.

alignas e _Alignas (C11)

Use alignas ou _Alignas para especificar o alinhamento personalizado para um tipo definido pelo usuário ou variável. Eles podem ser aplicados a um struct, união, enumeração ou variável.

Sintaxe de alignas

alignas(type)
alignas(constant-expression)
_Alignas(type)
_Alignas(constant-expression)

Comentários

_Alignas não pode ser usado na declaração de um typedef, campo de bit, função, parâmetro de função ou um objeto declarado com o especificador register.

Especifique um alinhamento que seja uma potência de dois, como 1, 2, 4, 8, 16 e assim por diante. Não use um valor menor que o tamanho do tipo.

Os tipos struct e union têm um alinhamento igual ao maior alinhamento de qualquer membro. Bytes de preenchimento são adicionados dentro de um struct para garantir que os requisitos de alinhamento de membros individuais sejam atendidos.

Se houver vários especificadores alignas em uma declaração (por exemplo, um struct com vários membros que têm especificadores alignas diferentes), o alinhamento do struct será pelo menos o valor do maior especificador.

Exemplo do alignas

Este exemplo usa a macro alignof de conveniência porque ela é portátil para C++. O comportamento será o mesmo se você usar _Alignof.

// Compile with /std:c11

#include <stdio.h>
#include <stdalign.h>

typedef struct 
{
    int value; // aligns on a 4-byte boundary. There will be 28 bytes of padding between value and alignas
    alignas(32) char alignedMemory[32]; // assuming a 32 byte friendly cache alignment
} cacheFriendly; // this struct will be 32-byte aligned because alignedMemory is 32-byte aligned and is the largest alignment specified in the struct

int main()
{
    printf("sizeof(cacheFriendly): %d\n", sizeof(cacheFriendly)); // 4 bytes for int value + 32 bytes for alignedMemory[] + padding to ensure  alignment
    printf("alignof(cacheFriendly): %d\n", alignof(cacheFriendly)); // 32 because alignedMemory[] is aligned on a 32-byte boundary

    /* output
        sizeof(cacheFriendly): 64
        alignof(cacheFriendly): 32
    */
}

alignof e _Alignof (C11)

_Alignof e seu alias alignof retornam o alinhamento em bytes do tipo especificado. Retornam um valor de tipo size_t.

Sintaxe de alignof

alignof(type)
_Alignof(type)

Exemplo do alignof

Este exemplo usa a macro alignof de conveniência porque ela é portátil para C++. O comportamento será o mesmo se você usar _Alignof.

// Compile with /std:c11

#include <stdalign.h>
#include <stdio.h>

int main()
{
    size_t alignment = alignof(short);
    printf("alignof(short) = %d\n", alignment); // 2
    printf("alignof(int) = %d\n", alignof(int)); // 4
    printf("alignof(long) = %d\n", alignof(long)); // 4
    printf("alignof(float) = %d\n", alignof(float)); // 4
    printf("alignof(double) = %d\n", alignof(double)); // 8

    typedef struct
    {
        int a;
        double b;
    } test;

    printf("alignof(test) = %d\n", alignof(test)); // 8 because that is the alignment of the largest element in the structure

    /* output
        
       alignof(short) = 2
       alignof(int) = 4
       alignof(long) = 4
       alignof(float) = 4
       alignof(double) = 8
       alignof(test) = 8
    */
}

Requisitos

Compilar com /std:c11.

O SDK do Windows 10.0.20348.0 (versão 2104) ou posterior. Consulte o SDK do Windows para baixar o SDK mais recente. Para obter instruções sobre como instalar e usar o SDK para desenvolvimento C11 e C17, consulte Instalar o suporte C11 e C17 no Visual Studio.

Confira também

/std (Especificar a versão padrão da linguagem)
C++ alignof e alignas
Tratamento do compilador de alinhamento de dados