integer overflow at comptime — Como Resolver em Zig
O Que Este Erro Significa
O erro de integer overflow em tempo de compilação ocorre quando uma operação aritmética realizada durante a compilação produz um resultado que não cabe no tipo inteiro utilizado. Diferente de muitas linguagens que simplesmente “envolvem” o valor (wrap around) silenciosamente, Zig detecta overflow tanto em tempo de compilação quanto em tempo de execução (modo Debug) e o trata como erro.
Em comptime, o Zig é ainda mais rigoroso: como o cálculo acontece durante a compilação, o compilador pode verificar com certeza absoluta que ocorreu overflow e rejeita o código.
Causas Comuns
1. Multiplicação que Excede o Tipo
pub fn main() void {
const x: u8 = 200;
const y: u8 = 2;
const resultado = x * y; // ERRO: 200 * 2 = 400, que não cabe em u8 (max 255)
_ = resultado;
}
2. Soma que Excede o Limite
pub fn main() void {
const a: u8 = 250;
const b: u8 = 10;
const c = a + b; // ERRO: 250 + 10 = 260, não cabe em u8
_ = c;
}
3. Subtração com Resultado Negativo em Unsigned
pub fn main() void {
const x: u32 = 5;
const y: u32 = 10;
const diff = x - y; // ERRO: 5 - 10 = -5, não pode ser representado em u32
_ = diff;
}
4. Shift que Excede o Tamanho
pub fn main() void {
const x: u8 = 1;
const resultado = x << 8; // ERRO: shift de 8 bits em u8 (max shift é 7)
_ = resultado;
}
5. Literal comptime_int que Não Cabe no Tipo Destino
pub fn main() void {
const x: u8 = 256; // ERRO: 256 não cabe em u8 (range: 0-255)
_ = x;
}
6. Cálculos em Constantes Globais
const TAMANHO_PAGINA: u16 = 4096;
const NUM_PAGINAS: u16 = 20;
const TOTAL: u16 = TAMANHO_PAGINA * NUM_PAGINAS; // ERRO: 81920 não cabe em u16
Como Corrigir
Solução 1: Usar um Tipo Maior
A solução mais comum é usar um tipo que comporte o resultado:
pub fn main() void {
const x: u16 = 200; // u16 ao invés de u8
const y: u16 = 2;
const resultado = x * y; // OK: 400 cabe em u16
_ = resultado;
}
Solução 2: Usar Aritmética com @intCast
Quando o resultado intermediário é maior mas o resultado final cabe:
pub fn main() void {
const x: u8 = 200;
const y: u8 = 2;
const temp: u16 = @as(u16, x) * @as(u16, y); // Calcula em u16
// Se precisar converter de volta para u8, apenas se couber
_ = temp;
}
Solução 3: Usar Operações Saturantes
Zig oferece operadores com saturação que limitam ao valor máximo/mínimo:
pub fn main() void {
const x: u8 = 200;
const y: u8 = 2;
const resultado = x +| y; // Saturante: resultado máximo é 255
// +| (soma saturante), -| (subtração saturante), *| (multiplicação saturante)
_ = resultado;
}
Solução 4: Usar Operações com Wrap (Envolvimento)
Se o comportamento de wrap-around é o desejado:
pub fn main() void {
const x: u8 = 200;
const y: u8 = 100;
const resultado = x +% y; // Wrap: (200 + 100) % 256 = 44
// +% (soma com wrap), -% (subtração com wrap), *% (multiplicação com wrap)
_ = resultado;
}
Solução 5: Verificar Antes de Operar
const std = @import("std");
pub fn main() void {
const x: u8 = 200;
const y: u8 = 100;
const resultado = @addWithOverflow(x, y);
if (resultado[1] != 0) {
std.debug.print("overflow detectado!\n", .{});
} else {
std.debug.print("resultado: {}\n", .{resultado[0]});
}
}
Solução 6: Corrigir Constantes Globais
const TAMANHO_PAGINA: u32 = 4096; // u32 ao invés de u16
const NUM_PAGINAS: u32 = 20;
const TOTAL: u32 = TAMANHO_PAGINA * NUM_PAGINAS; // OK: 81920 cabe em u32
Tabela de Referência: Limites dos Tipos Inteiros
| Tipo | Mínimo | Máximo |
|---|---|---|
| u8 | 0 | 255 |
| u16 | 0 | 65,535 |
| u32 | 0 | 4,294,967,295 |
| u64 | 0 | 18.4 quintilhões |
| i8 | -128 | 127 |
| i16 | -32,768 | 32,767 |
| i32 | -2,147,483,648 | 2,147,483,647 |
Operadores Aritméticos Especiais do Zig
| Operador | Tipo | Descrição |
|---|---|---|
+ | Normal | Erro em overflow (Debug) / UB (Release) |
+% | Wrapping | Envolve ao estourar |
| `+ | ` | Saturating |
Erros Relacionados
- integer overflow at runtime — Overflow detectado em tempo de execução
- integer truncation — Truncamento ao converter entre tipos
- signed/unsigned mismatch — Conflito entre tipos com/sem sinal