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, só 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 CReordenar 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| Modo | Use 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 |