---
title: "@shrExact em Zig — Referência e Exemplos"
url: "https://ziglang.com.br/builtins/@shrexact-em-zig-refer%C3%AAncia-e-exemplos/"
markdown_url: "https://ziglang.com.br/builtins/@shrexact-em-zig-refer%C3%AAncia-e-exemplos.MD"
description: "Referência completa do @shrExact em Zig. Shift right exato que garante que nenhum bit significativo é perdido. Exemplos práticos pt-BR."
date: "2026-02-21"
author: "Zig Brasil"
---

# @shrExact em Zig — Referência e Exemplos

Referência completa do @shrExact em Zig. Shift right exato que garante que nenhum bit significativo é perdido. Exemplos práticos pt-BR.


# @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

```zig
@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

```zig
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

```zig
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

```zig
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.

## Diferença entre `@shrExact` e o operador `>>`

O operador `>>` padrão em Zig descarta silenciosamente quaisquer bits deslocados para fora. Isso é aceitável em muitos contextos, mas `@shrExact` adiciona a garantia de que o descarte não ocorre — se algum bit 1 for perdido, o programa falha de forma detectável.

Essa distinção é análoga a `@shlExact`: o "Exact" comunica que o shift é matematicamente exato (equivalente a uma divisão inteira sem resto).

## Uso para divisão inteira verificada

`@shrExact(x, n)` é equivalente a `x / 2^n`, mas apenas quando `x` é divisível por `2^n`. Use quando a divisibilidade for uma invariante do algoritmo:

```zig
const std = @import("std");

// Converter bytes para palavras de 4 bytes (deve ser múltiplo de 4)
fn bytesParaPalavras(bytes: u32) u32 {
    // @shrExact garante que bytes é múltiplo de 4
    // Se não for, panic em safe mode — indicando bug no código
    return @shrExact(bytes, 2);
}

// Converter bytes para kilobytes (deve ser múltiplo de 1024)
fn bytesParaKb(bytes: usize) usize {
    return @shrExact(bytes, 10);
}
```

## Comparação com equivalente em C

Em C, shift right não verifica se bits são perdidos:

```c
// C: shift right silencioso
unsigned int resultado = 7 >> 1; // 3, mas o bit 0 foi perdido silenciosamente

// C: verificar divisibilidade antes (extra overhead)
unsigned int valor = 7;
if (valor % 2 != 0) {
    // não é exatamente divisível
}
unsigned int resultado = valor >> 1;
```

Em Zig, `@shrExact` documenta e verifica a intenção:

```zig
// Zig: explícito — queremos divisão exata
const resultado = @shrExact(@as(u32, 8), 1); // ok: 4
// @shrExact(@as(u32, 7), 1) causaria panic — 7 é ímpar
```

## Casos de uso em protocolos de rede

Campos de comprimento em cabeçalhos binários frequentemente codificam tamanhos em múltiplos de unidades maiores (palavras de 4 bytes, blocos de 512 bytes). `@shrExact` é ideal para decodificá-los:

```zig
const std = @import("std");

// Cabeçalho IP: campo IHL está em palavras de 32 bits
const CabecalhoIP = packed struct {
    ihl: u4,   // Internet Header Length em palavras de 32 bits
    versao: u4,
    // ... outros campos
};

fn tamanhoHeaderBytes(ihl: u4) u8 {
    // ihl * 4 bytes por palavra; o inverso deve ser exato
    return @as(u8, ihl) * 4;
}

fn ihlDoTamanho(tamanho_bytes: u8) u4 {
    // Tamanho deve ser múltiplo de 4
    const ihl = @shrExact(@as(u32, tamanho_bytes), 2);
    return @intCast(ihl);
}
```

## Erros comuns

**1. Usar `@shrExact` quando o valor pode ter bits inferiores não-zero:**
```zig
var valor: u32 = lerDaRede(); // valor desconhecido em runtime

// PERIGOSO se valor pode não ser múltiplo de 4:
const resultado = @shrExact(valor, 2); // panic potencial

// SEGURO: verificar primeiro ou usar >> se descarte é aceitável
const resultado = if (valor % 4 == 0) @shrExact(valor, 2) else valor >> 2;
```

**2. Confundir com divisão aritmética para tipos signed:** Para inteiros negativos, `>>` é aritmético (preserva o sinal) em Zig. `@shrExact` ainda requer que os bits descartados sejam zero, mas bits inferiores de números negativos em complemento de dois podem ser não-zero mesmo para valores "múltiplos".

## Perguntas Frequentes

**P: `@shrExact` é mais lento que `>>`?**

R: Em modo Debug/ReleaseSafe, `@shrExact` adiciona uma verificação extra (testar se os bits inferiores são zero). Em ReleaseFast, o comportamento é o mesmo que `>>`, sem overhead — o compilador emite apenas a instrução de shift.

**P: Posso usar `@shrExact` em comptime?**

R: Sim. Em comptime, se o valor não for exatamente divisível, o compilador emite um erro de compilação — o que é ainda melhor que um panic em runtime.

**P: Qual a relação entre `@shrExact` e `@ctz`?**

R: `@ctz` (count trailing zeros) conta quantos zeros existem nos bits inferiores, o que indica a maior potência de 2 pela qual o valor é divisível. Você pode usar `@ctz(x) >= n` para verificar se `@shrExact(x, n)` seria seguro sem causar panic.

## Builtins relacionados

- [@shlExact](/builtins/shl-exact/) — Shift left exato
- [@clz](/builtins/clz/) — Contar zeros à esquerda
- [@ctz](/builtins/ctz/) — Contar zeros à direita
- [@popCount](/builtins/pop-count/) — Contar bits em 1

## Tutoriais relacionados

- [Operações Bit a Bit em Zig](/tutoriais/bitwise-zig/)
- [Sistema de Tipos do Zig](/tutoriais/tipos/)
- [Introdução ao Zig](/tutoriais/introducao-ao-zig/)
