Sentinel em Zig — O que é e Como Usar
Definição
Um sentinel-terminated array (array terminado por sentinela) em Zig é um array ou slice que possui um valor especial — o sentinel — imediatamente após o último elemento. O exemplo mais comum é a string terminada em zero ([:0]u8), equivalente às strings C (char* com \0 no final).
A sintaxe [N:s]T declara um array de N elementos do tipo T com sentinela s. Para slices, [:s]T indica um slice com sentinel.
Por que Sentinels Importam
- Interoperabilidade com C: APIs C esperam strings terminadas em null. Zig facilita a criação e uso desses tipos.
- Segurança de tipos: O tipo carrega a informação do sentinel, garantindo em tempo de compilação que o terminador está presente.
- Compatibilidade: Sentinel-terminated slices podem ser convertidos para slices normais sem custo.
- String literals: Todas as string literals em Zig são
*const [N:0]u8— terminadas em zero automaticamente.
Exemplo Prático
Strings Terminadas em Zero
const std = @import("std");
pub fn main() void {
// String literal é automaticamente sentinel-terminated
const mensagem: [:0]const u8 = "Olá, Zig!";
// Acessar o sentinel
std.debug.print("Último char: '{}'\n", .{mensagem[mensagem.len]}); // 0
// Passar para função C
_ = std.c.printf("%s\n", mensagem.ptr);
}
Arrays com Sentinel Customizado
// Array de 3 elementos terminado com 0xFF
const dados: [3:0xFF]u8 = .{ 10, 20, 30 };
// O elemento na posição [3] é 0xFF (o sentinel)
std.debug.print("Sentinel: {}\n", .{dados[3]}); // 255
Convertendo entre Tipos
const std = @import("std");
pub fn main() void {
// Sentinel-terminated → slice normal (sem custo)
const sentinel_slice: [:0]const u8 = "Zig Brasil";
const slice_normal: []const u8 = sentinel_slice;
_ = slice_normal;
// Array → sentinel slice
var array: [5:0]u8 = .{ 'H', 'e', 'l', 'l', 'o' };
const s: [:0]u8 = &array;
_ = s;
}
Interop com C
const std = @import("std");
const c = @cImport({
@cInclude("stdio.h");
@cInclude("string.h");
});
pub fn main() void {
const zig_string: [:0]const u8 = "Texto do Zig";
// strlen espera [*:0]const u8 — compatível automaticamente
const tamanho = c.strlen(zig_string);
std.debug.print("Tamanho via C: {}\n", .{tamanho});
}
Criando Sentinel Slice Dinamicamente
fn criarStringC(allocator: std.mem.Allocator, texto: []const u8) ![:0]u8 {
const resultado = try allocator.allocSentinel(u8, texto.len, 0);
@memcpy(resultado, texto);
return resultado;
}
Tipos com Sentinel
| Tipo | Descrição |
|---|---|
[N:0]u8 | Array de N bytes + null terminator |
[:0]u8 | Slice de bytes com null terminator |
[*:0]u8 | Many-pointer terminado em null |
[N:s]T | Array de N elementos com sentinel s |
Armadilhas Comuns
- Assumir que todo
[]const u8é terminado em zero: Slices normais NÃO têm sentinel. Só[:0]const u8garante o terminador. - Acessar além do sentinel: O sentinel está em
slice[slice.len], mas acessarslice[slice.len + 1]é comportamento indefinido. - Esquecer de usar
allocSentinel: Ao alocar memória para strings que serão passadas para C, useallocSentinelem vez dealloc. - Converter sem cuidado: Converter
[]u8para[:0]u8requer que o sentinela realmente exista na memória. Usestd.mem.sliceTopara conversão segura.
Termos Relacionados
- Slice — Referência a sequência de memória
- Pointer Types — Tipos de ponteiro em Zig
- usize — Tipo de índice e comprimento