Undefined em Zig — O que é e Como Usar
Definição
O valor undefined em Zig é um marcador especial que indica que uma variável não foi inicializada. Quando você atribui undefined a uma variável, está explicitamente dizendo ao compilador: “eu sei que este valor não tem conteúdo válido ainda, e me comprometo a inicializá-lo antes de usar”.
Em modo Debug e ReleaseSafe, variáveis undefined são preenchidas com 0xAA (padrão facilmente reconhecível em depuração). Em ReleaseFast e ReleaseSmall, undefined permite que o compilador otimize livremente, podendo resultar em qualquer valor.
Por que Undefined Importa
- Performance: Evita inicialização desnecessária de buffers grandes que serão preenchidos imediatamente.
- Explicitação: Torna claro que a não-inicialização é intencional, não um bug.
- Detecção de bugs: Em modo Debug, o padrão
0xAAajuda a identificar uso acidental. - Compatibilidade com C: Permite o mesmo padrão de “declara depois inicializa” comum em C.
Exemplo Prático
Uso com Buffers
const std = @import("std");
pub fn main() !void {
// Buffer que será preenchido pela leitura
var buffer: [1024]u8 = undefined;
const stdin = std.io.getStdIn();
const bytes_lidos = try stdin.read(&buffer);
// Agora só a parte preenchida é válida
const entrada = buffer[0..bytes_lidos];
std.debug.print("Lido: {s}\n", .{entrada});
}
Uso com Arrays Calculados
fn calcularTabela() [256]u8 {
var tabela: [256]u8 = undefined;
for (0..256) |i| {
tabela[i] = @intCast(i ^ 0xFF); // Preenche cada posição
}
return tabela;
}
const TABELA = calcularTabela();
Uso com Structs
const Conexao = struct {
socket: std.posix.socket_t,
buffer: [4096]u8,
bytes_recebidos: usize,
pub fn init(endereco: []const u8) !Conexao {
var self: Conexao = undefined;
self.socket = try conectar(endereco);
self.bytes_recebidos = 0;
// buffer será preenchido quando dados chegarem
return self;
}
};
Comparação: undefined vs Zero-init
// undefined — sem custo, mas perigoso se não inicializar
var buffer1: [1_000_000]u8 = undefined;
// Zero-init — seguro, mas gasta tempo zerando 1MB
var buffer2: [1_000_000]u8 = std.mem.zeroes([1_000_000]u8);
// Ou com @memset
var buffer3: [1_000_000]u8 = undefined;
@memset(&buffer3, 0);
O que Acontece em Cada Modo
| Modo | Valor de undefined | Verificação |
|---|---|---|
| Debug | 0xAA repetido | Sim (panic ao detectar uso) |
| ReleaseSafe | 0xAA repetido | Sim |
| ReleaseFast | Lixo de memória | Não |
| ReleaseSmall | Lixo de memória | Não |
Armadilhas Comuns
- Ler antes de inicializar: Em Release,
undefinedpode ser qualquer valor — ler sem inicializar é comportamento indefinido. Em Debug, causa panic. - Passar
undefinedpara funções: Se uma função espera um valor válido e recebeundefined, o comportamento é indefinido. - Confundir com
null:nullé um valor válido para optionals;undefinedsignifica “sem valor algum”. - Uso excessivo: Não use
undefinedcomo “default” para tudo. Se há um valor inicial razoável, use-o. - Retornar
undefined: Retornarundefinedde uma função é quase sempre um bug. O chamador esperará um valor válido.
Termos Relacionados
- Unreachable — Código que nunca deveria executar
- Optional — Tipo que pode ser null
- Allocator — Alocação de memória
- Stack vs Heap — Onde a memória vive