Signed/Unsigned Mismatch — Como Resolver em Zig
O Que Este Erro Significa
O erro de signed/unsigned mismatch ocorre quando o código tenta usar um tipo inteiro com sinal (signed, como i32) onde um tipo sem sinal (unsigned, como u32) é esperado, ou vice-versa. Zig não faz conversão automática entre tipos signed e unsigned porque essa conversão pode perder informação ou mudar o significado do valor.
Mensagens típicas do compilador:
error: expected type 'u32', found 'i32'
error: signed-unsigned mismatch in operands
Em C, essa conversão é feita silenciosamente e é fonte de inúmeros bugs. Zig exige que o programador seja explícito sobre suas intenções.
Causas Comuns
1. Atribuir Valor Signed a Variável Unsigned
pub fn main() void {
const a: i32 = 42;
const b: u32 = a; // ERRO: i32 pode ser negativo
_ = b;
}
2. Passar Argumento de Tipo Errado
fn processar(indice: usize) void {
_ = indice;
}
pub fn main() void {
const i: i32 = 5;
processar(i); // ERRO: esperado usize, recebeu i32
}
3. Comparar Signed com Unsigned
pub fn main() void {
const a: i32 = -1;
const b: u32 = 5;
const resultado = a < b; // ERRO: não pode comparar i32 com u32 diretamente
_ = resultado;
}
4. Operação Aritmética entre Tipos Misturados
pub fn main() void {
const a: i32 = 10;
const b: u32 = 5;
const soma = a + b; // ERRO: operandos de tipos diferentes
_ = soma;
}
5. Índice de Array com Tipo Signed
pub fn main() void {
const arr = [_]u8{ 1, 2, 3 };
const i: i32 = 1;
const val = arr[i]; // ERRO: índice deve ser usize
_ = val;
}
Como Corrigir
Solucao 1: Usar @intCast (Quando o Valor É Garantidamente Válido)
pub fn main() void {
const a: i32 = 42;
const b: u32 = @intCast(a); // OK se a >= 0, PANIC se a < 0
_ = b;
}
Solucao 2: Verificar Antes de Converter
const std = @import("std");
pub fn main() void {
const a: i32 = -5;
if (a >= 0) {
const b: u32 = @intCast(a);
std.debug.print("Convertido: {}\n", .{b});
} else {
std.debug.print("Valor negativo: {}\n", .{a});
}
}
Solucao 3: Usar std.math.cast para Conversão Segura
const std = @import("std");
pub fn main() void {
const a: i32 = -5;
const b: ?u32 = std.math.cast(u32, a);
const valor = b orelse {
std.debug.print("Não pode converter {} para u32\n", .{a});
return;
};
std.debug.print("Convertido: {}\n", .{valor});
}
Solucao 4: Uniformizar Tipos na Declaração
pub fn main() void {
// Use o mesmo tipo desde o início
const a: u32 = 42;
const b: u32 = 10;
const soma = a + b; // Sem conflito de tipos
_ = soma;
}
Solucao 5: Converter para Tipo Comum Antes de Operar
pub fn main() void {
const a: i32 = 10;
const b: u32 = 5;
// Converte ambos para um tipo que suporte os dois
const a_64: i64 = a;
const b_64: i64 = @intCast(b);
const soma = a_64 + b_64;
_ = soma;
}
Solucao 6: @bitCast para Reinterpretação de Bits
pub fn main() void {
// Quando quer o mesmo padrão de bits com outro tipo
const a: i32 = -1;
const b: u32 = @bitCast(a); // b == 4294967295 (0xFFFFFFFF)
_ = b;
// E vice-versa
const c: u32 = 4294967295;
const d: i32 = @bitCast(c); // d == -1
_ = d;
}
Armadilhas Comuns em C (Evitadas por Zig)
Em C, a conversão silenciosa causa bugs sutis:
// C — bugs silenciosos
unsigned int a = 0;
int b = -1;
if (b < a) { // FALSO em C! -1 vira 4294967295
printf("correto");
}
Em Zig, esse código simplesmente não compila, obrigando o programador a lidar com a questão:
pub fn main() void {
const a: u32 = 0;
const b: i32 = -1;
// Zig: ERRO DE COMPILAÇÃO — comparação signed/unsigned
// O programador DEVE decidir como tratar
_ = a;
_ = b;
}
Tabela de Conversões
| De | Para | Método | Risco |
|---|---|---|---|
i32 positivo | u32 | @intCast | Panic se negativo |
u32 | i32 | @intCast | Panic se > MAX_i32 |
i32 | u32 | @bitCast | Reinterpreta bits |
i32/u32 | i64 | Coerção automática | Nenhum (widening) |
i32 qualquer | ?u32 | std.math.cast | Retorna null se inválido |
Quando Usar Cada Tipo
u32,u64,usize: Contadores, índices, tamanhos, quantidades que nunca são negativasi32,i64: Diferenças, coordenadas, valores que podem ser negativosusize: Índices de array, tamanhos de memória (obrigatório para indexação)
pub fn main() void {
// Padrão idiomático em Zig
const tamanho: usize = 100; // Tamanhos são sempre usize
const indice: usize = 0; // Índices são sempre usize
const diferenca: i64 = -5; // Diferenças podem ser negativas
const contagem: u32 = 42; // Contagens são unsigned
_ = tamanho;
_ = indice;
_ = diferenca;
_ = contagem;
}
Erros Relacionados
- Type coercion failed — Falha na coerção de tipos
- Integer truncation — Truncamento de inteiro
- Integer overflow at runtime — Overflow em runtime
- Type mismatch assignment — Tipo incompatível