@shrExact em Zig — Referência e Exemplos

@shrExact em Zig

O @shrExact realiza um shift right (deslocamento à direita) e garante que nenhum bit significativo é perdido (descartado pela parte inferior). Se algum bit 1 for deslocado para fora (ou seja, se os bits inferiores não forem zero), causa panic em modo safe. É a versão “exata” do shift right.

Sintaxe

@shrExact(value: T, shift_amt: Log2T) T

Parâmetros

  • value (T): Valor inteiro a ser deslocado.
  • shift_amt (Log2T): Número de posições para deslocar à direita.

Valor de retorno

Retorna T — o resultado do shift right, garantindo que bits descartados eram zero.

Exemplos práticos

Exemplo 1: Divisão exata por potência de 2

const std = @import("std");

pub fn main() void {
    // 16 >> 2 = 4 (exato, sem perda)
    const a: u8 = @shrExact(@as(u8, 16), 2);
    std.debug.print("16 >> 2 = {}\n", .{a}); // 4

    // 64 >> 3 = 8 (exato)
    const b: u32 = @shrExact(@as(u32, 64), 3);
    std.debug.print("64 >> 3 = {}\n", .{b}); // 8

    // Isso causaria panic em safe mode:
    // @shrExact(@as(u8, 7), 1) — 7 é ímpar, bit inferior seria perdido!
}

Exemplo 2: Extrair campo de bits alinhado

const std = @import("std");

fn extrairByte(valor: u32, posicao: u5) u8 {
    // Posição deve ser múltiplo de 8
    const deslocado = @shrExact(valor & (@as(u32, 0xFF) << posicao), posicao);
    return @intCast(deslocado);
}

pub fn main() void {
    const valor: u32 = 0xAABBCCDD;
    std.debug.print("Byte 0: 0x{X:0>2}\n", .{extrairByte(valor, 0)});  // DD
    std.debug.print("Byte 8: 0x{X:0>2}\n", .{extrairByte(valor, 8)});  // CC
    std.debug.print("Byte 16: 0x{X:0>2}\n", .{extrairByte(valor, 16)}); // BB
}

Exemplo 3: Verificar alinhamento

const std = @import("std");

fn verificarAlinhamento(endereco: usize, comptime alinhamento: u6) bool {
    // Se o endereço é alinhado, os bits inferiores são zero
    // @shrExact só funciona se os bits inferiores forem zero
    const mascara = (@as(usize, 1) << alinhamento) - 1;
    return (endereco & mascara) == 0;
}

pub fn main() void {
    std.debug.print("16 alinhado a 4? {}\n", .{verificarAlinhamento(16, 2)});   // true
    std.debug.print("17 alinhado a 4? {}\n", .{verificarAlinhamento(17, 2)});   // false
    std.debug.print("256 alinhado a 16? {}\n", .{verificarAlinhamento(256, 4)}); // true
}

Casos de uso comuns

  1. Divisão exata por potência de 2: Quando se sabe que o resultado é inteiro.
  2. Extração de campos de bits: Deslocar campos alinhados de registradores.
  3. Conversão de unidades: Bytes para KB (shift 10) quando o valor é múltiplo.
  4. Decodificação de protocolos: Extrair campos de cabeçalhos binários.

Builtins relacionados

Tutoriais relacionados

Continue aprendendo Zig

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