Pular para o conteúdo

Alinhamento e enchimento

Por que u8 + u32 + u16 ocupa 12 bytes e não 7, como reduzir, e quando empacotar.

O processador lê um u32 mais depressa — e em algumas arquiteturas, consegue lê-lo — quando ele começa num endereço múltiplo de 4. O compilador de C insere bytes vazios entre os campos para garantir isso, e também no fim do registro, para um vetor deles continuar alinhado. Esses bytes são o enchimento.

dataforge
adopt Arcane.Estrutura as Est
adopt Arcane.C as C

campos := [["a", "u8"], ["b", "u32"], ["c", "u16"]]
alinhado := Est.definir("S", campos, "intel")
out alinhado.mapa()

assert alinhado.tamanho is 12                  // u8, três vazios, u32, u16, dois vazios
assert alinhado.enchimento() is 5
assert alinhado.tamanho is C.estrutura(campos).tamanho()   // o mesmo que o C faria

empacotado := Est.definir("S", campos, "intel", yes)
assert empacotado.tamanho is 7                 // o '#pragma pack(1)' do C

Reordenar custa zero e economiza#

Os mesmos campos, do maior para o menor, deixam de precisar de enchimento no meio. Num vetor de um milhão de registros, isso é um terço da memória:

dataforge
adopt Arcane.Estrutura as Est

bagunçado := Est.definir("A", [["a", "u8"], ["b", "u32"], ["c", "u16"]], "intel")
ordenado := Est.definir("B", [["b", "u32"], ["c", "u16"], ["a", "u8"]], "intel")
assert bagunçado.tamanho is 12 and ordenado.tamanho is 8
ModoUse quando
alinhado (padrão)o registro vai para uma struct do C, ou vive na memória em vetor
empacotado (yes)o formato de arquivo ou protocolo foi definido sem enchimento — quase todos