@bitSizeOf em Zig — Referência e Exemplos

@bitSizeOf em Zig

O @bitSizeOf retorna o tamanho de um tipo em bits, sem incluir padding de alinhamento. Diferente de @sizeOf, que retorna bytes incluindo padding, @bitSizeOf retorna a quantidade exata de bits que compõem o tipo. Isso é particularmente útil ao trabalhar com tipos de bits não-padrão como u3, u24 ou i12.

Sintaxe

@bitSizeOf(comptime T: type) comptime_int

O que faz

O @bitSizeOf consulta a quantidade exata de bits que um tipo usa para representar seus dados, sem considerar bytes de padding adicionados para alinhamento. Para tipos padrão como u32, o resultado é simplesmente 32. Para tipos como u24, retorna 24 (enquanto @sizeOf retornaria 4 bytes = 32 bits, incluindo padding).

Parâmetros

  • T (type, comptime): O tipo cujo tamanho em bits será consultado.

Valor de retorno

Retorna um comptime_int representando o número exato de bits do tipo.

Exemplos práticos

Exemplo 1: Comparação com @sizeOf

const std = @import("std");

test "bitSizeOf vs sizeOf" {
    // Para tipos alinhados, bitSizeOf == sizeOf * 8
    try std.testing.expect(@bitSizeOf(u8) == 8);
    try std.testing.expect(@bitSizeOf(u16) == 16);
    try std.testing.expect(@bitSizeOf(u32) == 32);
    try std.testing.expect(@bitSizeOf(u64) == 64);

    // Para tipos de bits arbitrários, os valores diferem
    try std.testing.expect(@bitSizeOf(u24) == 24);
    try std.testing.expect(@sizeOf(u24) == 4);  // 4 bytes com padding

    try std.testing.expect(@bitSizeOf(u3) == 3);
    try std.testing.expect(@sizeOf(u3) == 1);  // 1 byte mínimo

    try std.testing.expect(@bitSizeOf(bool) == 1);
    try std.testing.expect(@sizeOf(bool) == 1);  // 1 byte mínimo
}

Exemplo 2: Packed structs e layout de bits

const std = @import("std");

const Flags = packed struct {
    leitura: bool,      // 1 bit
    escrita: bool,      // 1 bit
    execucao: bool,     // 1 bit
    especial: bool,     // 1 bit
    reservado: u4,      // 4 bits
};

const CorRGB565 = packed struct {
    vermelho: u5,    // 5 bits
    verde: u6,       // 6 bits
    azul: u5,        // 5 bits
};

test "tamanho de packed structs" {
    // Packed structs empacotam campos sem padding
    try std.testing.expect(@bitSizeOf(Flags) == 8);
    try std.testing.expect(@sizeOf(Flags) == 1);

    try std.testing.expect(@bitSizeOf(CorRGB565) == 16);
    try std.testing.expect(@sizeOf(CorRGB565) == 2);
}

Exemplo 3: Cálculos de capacidade de armazenamento

const std = @import("std");

fn bitsParaArmazenar(comptime T: type, n: usize) usize {
    return @bitSizeOf(T) * n;
}

fn bytesNecessarios(comptime T: type, n: usize) usize {
    const total_bits = bitsParaArmazenar(T, n);
    return (total_bits + 7) / 8; // Arredondar para cima
}

test "cálculo de armazenamento" {
    // 10 valores u12 precisam de 120 bits = 15 bytes
    try std.testing.expect(bitsParaArmazenar(u12, 10) == 120);
    try std.testing.expect(bytesNecessarios(u12, 10) == 15);

    // 8 valores bool precisam de 8 bits = 1 byte
    try std.testing.expect(bitsParaArmazenar(bool, 8) == 8);
    try std.testing.expect(bytesNecessarios(bool, 8) == 1);

    // 3 valores u3 precisam de 9 bits = 2 bytes
    try std.testing.expect(bitsParaArmazenar(u3, 3) == 9);
    try std.testing.expect(bytesNecessarios(u3, 3) == 2);
}

Casos de uso comuns

  1. Packed structs: Verificar o tamanho exato de campos empacotados para protocolos binários.
  2. Formatos de imagem: Trabalhar com formatos de cor como RGB565 (16 bits) ou RGB555 (15 bits).
  3. Compressão de dados: Calcular o espaço mínimo necessário para armazenar dados com tipos de bits arbitrários.
  4. Protocolos de comunicação: Definir e verificar layouts de bits em cabeçalhos de protocolo.
  5. Hardware e registradores: Validar que campos de registradores packed ocupam a quantidade correta de bits.

Diferença entre @bitSizeOf e @sizeOf — resumo visual

Tipo: u24

@bitSizeOf(u24) = 24    ← bits reais do valor
@sizeOf(u24)    = 4     ← bytes em memória (inclui 8 bits de padding)

Tipo: bool

@bitSizeOf(bool) = 1    ← apenas 1 bit de informação
@sizeOf(bool)    = 1    ← mas ocupa 1 byte completo em memória

Tipo: packed struct { a: u3, b: u5 }

@bitSizeOf(T) = 8       ← 3 + 5 = 8 bits exatos
@sizeOf(T)    = 1       ← 8 bits = 1 byte, sem padding

Equivalente em C

C não tem equivalente direto para @bitSizeOf. O sizeof do C corresponde ao @sizeOf do Zig (em bytes com padding). Para bit fields do C, o tamanho individual de cada campo não é acessível portavelmente:

// C: sizeof retorna bytes com padding
struct Flags {
    unsigned leitura  : 1;
    unsigned escrita  : 1;
    unsigned execucao : 1;
    unsigned reservado: 5;
};
// sizeof(struct Flags) == 4 (int, não 1 byte!)

Em Zig, usando packed struct, o comportamento é mais previsível e @bitSizeOf reflete os bits reais.

Uso com tipos de bits arbitrários

Zig suporta inteiros de qualquer largura de 0 a 65535 bits. O @bitSizeOf é essencial para trabalhar com esses tipos:

// Tipos de bits não-padrão
@bitSizeOf(u1)   // 1
@bitSizeOf(u3)   // 3
@bitSizeOf(u7)   // 7
@bitSizeOf(u12)  // 12
@bitSizeOf(u100) // 100
@bitSizeOf(u128) // 128

// Para esses tipos, @sizeOf arredonda para cima
@sizeOf(u1)   // 1 (1 byte mínimo)
@sizeOf(u7)   // 1
@sizeOf(u9)   // 2
@sizeOf(u100) // 16

Erros comuns

Usar @bitSizeOf quando precisa de @sizeOf para memcpy: Para operações de cópia de memória, você precisa de bytes, não bits. Use @sizeOf nesses casos.

Assumir que @bitSizeOf é sempre múltiplo de 8: Para tipos como u3 ou bool, @bitSizeOf retorna valores que não são múltiplos de 8. Se você precisar converter para bytes, arredonde para cima: (@bitSizeOf(T) + 7) / 8.

Perguntas Frequentes

@bitSizeOf funciona com structs normais (não packed)?

Sim, mas para structs normais o resultado é @sizeOf(T) * 8 — inclui os bits de padding. O valor mais útil de @bitSizeOf é com packed struct, onde não há padding.

Posso usar @bitSizeOf em tempo de compilação?

Sim. O resultado é sempre um comptime_int, disponível em qualquer contexto comptime. É frequentemente usado para calcular deslocamentos e tamanhos em manipulação de protocolos binários.

@bitSizeOf de u0 é zero?

Sim. @bitSizeOf(u0) == 0. Zig suporta o tipo u0, que tem apenas um valor possível (zero) e ocupa zero bits. É útil em código genérico onde um campo pode não existir.

Builtins relacionados

  • @sizeOf — Retorna o tamanho em bytes (com padding)
  • @alignOf — Retorna o alinhamento do tipo
  • @typeInfo — Informações completas sobre o tipo
  • @bitReverse — Inverte a ordem dos bits

Tutoriais relacionados

Continue aprendendo Zig

Explore mais tutoriais e artigos em português para dominar a linguagem Zig.