@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
- Divisão exata por potência de 2: Quando se sabe que o resultado é inteiro.
- Extração de campos de bits: Deslocar campos alinhados de registradores.
- Conversão de unidades: Bytes para KB (shift 10) quando o valor é múltiplo.
- Decodificação de protocolos: Extrair campos de cabeçalhos binários.
Builtins relacionados
- @shlExact — Shift left exato
- @clz — Contar zeros à esquerda
- @ctz — Contar zeros à direita
- @popCount — Contar bits em 1