Integer Truncation — Como Resolver em Zig
O Que Este Erro Significa
O erro de truncamento de inteiros ocorre quando você tenta converter um valor de um tipo inteiro maior para um tipo menor e o valor não cabe no tipo de destino. Em Zig, essa conversão nunca acontece silenciosamente — o compilador (em comptime) ou o runtime (em debug) detecta que bits significativos seriam perdidos e emite um erro.
Em tempo de compilação:
error: type 'u8' cannot represent the value '300'
Em runtime com @intCast:
thread 1 panic: integer cast truncated bits
Esse comportamento previne bugs sutis que são comuns em C, onde valores são silenciosamente truncados sem aviso.
Causas Comuns
1. Valor Literal Grande Demais para o Tipo
pub fn main() void {
const x: u8 = 300; // ERRO DE COMPILAÇÃO: 300 > 255 (max u8)
_ = x;
}
2. @intCast com Valor que Não Cabe
pub fn main() void {
const a: u32 = 1000;
const b: u8 = @intCast(a); // PANIC: 1000 não cabe em u8
_ = b;
}
3. Resultado de Operação Excede o Tipo
pub fn main() void {
const a: u16 = 50000;
const b: u16 = 30000;
const soma: u16 = a + b; // PANIC: 80000 > 65535 (max u16)
_ = soma;
}
4. Conversão de usize para Tipo Menor
pub fn main() void {
const tamanho: usize = 1_000_000;
const indice: u16 = @intCast(tamanho);
// PANIC em plataformas onde usize > 16 bits
_ = indice;
}
5. Truncamento em Retorno de Função
fn calcular() u8 {
var resultado: u32 = 500;
_ = &resultado;
return @intCast(resultado); // PANIC: 500 não cabe em u8
}
Como Corrigir
Solucao 1: Usar Tipo Grande o Suficiente
pub fn main() void {
const x: u16 = 300; // u16 suporta até 65535
_ = x;
}
Solucao 2: Usar @truncate para Truncamento Explícito
Quando você intencionalmente quer os bits inferiores:
pub fn main() void {
const a: u32 = 0x12345678;
const b: u8 = @truncate(a); // b = 0x78 (byte mais baixo)
_ = b;
}
Solucao 3: Verificar Antes de Converter
const std = @import("std");
pub fn main() void {
const valor: u32 = 1000;
if (valor <= std.math.maxInt(u8)) {
const pequeno: u8 = @intCast(valor);
std.debug.print("Convertido: {}\n", .{pequeno});
} else {
std.debug.print("Valor {} é grande demais para u8\n", .{valor});
}
}
Solucao 4: Usar std.math.cast (Retorna Optional)
const std = @import("std");
pub fn main() void {
const valor: u32 = 1000;
const resultado: ?u8 = std.math.cast(u8, valor);
if (resultado) |v| {
std.debug.print("Convertido: {}\n", .{v});
} else {
std.debug.print("Não cabe em u8\n", .{});
}
}
Solucao 5: Usar Saturação (@min/@max)
pub fn main() void {
const valor: u32 = 1000;
const saturado: u8 = @intCast(@min(valor, 255)); // Limita a 255
_ = saturado; // saturado == 255
}
Solucao 6: Usar Operações Saturantes
pub fn main() void {
const a: u8 = 200;
const b: u8 = 100;
const soma = a +| b; // Adição saturante: 255 (não 300)
_ = soma;
}
@intCast vs @truncate
| Operação | Comportamento | Quando Usar |
|---|---|---|
@intCast | Panic se bits são perdidos | Quando o valor DEVE caber |
@truncate | Descarta bits superiores silenciosamente | Quando quer os N bits inferiores |
pub fn main() void {
const x: u16 = 0x1234;
// @intCast — PANIC porque 0x1234 > 255
// const a: u8 = @intCast(x);
// @truncate — retorna 0x34 (byte inferior)
const b: u8 = @truncate(x); // b == 0x34
_ = b;
}
Truncamento em Comptime
Em comptime, qualquer truncamento é erro de compilação:
pub fn main() void {
// Comptime — erro de compilação
const a: u8 = 256; // ERRO: 256 não cabe em u8
// Runtime — panic em Debug
var b: u32 = 256;
_ = &b;
const c: u8 = @intCast(b); // PANIC em runtime
_ = a;
_ = c;
}
Operações Aritméticas Saturantes
Zig oferece operadores especiais que saturam ao invés de truncar:
pub fn main() void {
const a: u8 = 250;
// Operadores padrão — panic em overflow
// const b = a + 10; // PANIC: 260 > 255
// Operadores saturantes — limitam ao máximo
const c = a +| 10; // c == 255
const d = a *| 2; // d == 255
// Operadores wrapping — voltam ao início
const e = a +% 10; // e == 4 (260 % 256)
_ = c;
_ = d;
_ = e;
}
Erros Relacionados
- Integer overflow at comptime — Overflow em compilação
- Integer overflow at runtime — Overflow em runtime
- Type coercion failed — Falha na coerção de tipos
- Signed/unsigned mismatch — Mistura de tipos signed/unsigned