@alignCast em Zig
O @alignCast converte um ponteiro para ter um alinhamento diferente. É necessário quando você precisa converter ponteiros entre tipos com requisitos de alinhamento distintos — por exemplo, ao converter *anyopaque (alinhamento 1) para *u32 (alinhamento 4). Em modo safe, verifica em runtime se o endereço realmente está alinhado corretamente.
Sintaxe
@alignCast(ptr: anytype) DestType
O alinhamento de destino é inferido do contexto.
Parâmetros
- ptr (
anytype): Ponteiro cujo alinhamento será convertido.
Valor de retorno
Retorna o ponteiro com o novo alinhamento. Em modo Debug/ReleaseSafe, causa panic se o endereço não estiver alinhado.
Exemplos práticos
Exemplo 1: Converter *anyopaque para tipo alinhado
const std = @import("std");
fn callback(ctx: *anyopaque) void {
// *anyopaque tem alinhamento 1
// *u32 requer alinhamento 4
// @alignCast garante compatibilidade
const ptr: *u32 = @ptrCast(@alignCast(ctx));
std.debug.print("Valor: {}\n", .{ptr.*});
}
pub fn main() void {
var valor: u32 = 42;
callback(@ptrCast(&valor));
}
Exemplo 2: Combinando @ptrCast e @alignCast
const std = @import("std");
const Sensor = struct {
id: u32,
temperatura: f32,
};
fn processar(dados: [*]u8) void {
// Converter bytes para ponteiro de struct com alinhamento correto
const sensor: *Sensor = @ptrCast(@alignCast(dados));
std.debug.print("Sensor {}: {d:.1}°C\n", .{ sensor.id, sensor.temperatura });
}
pub fn main() void {
var sensor = Sensor{ .id = 1, .temperatura = 25.5 };
const bytes: [*]u8 = @ptrCast(&sensor);
processar(bytes);
}
Exemplo 3: Slice com alinhamento customizado
const std = @import("std");
fn processarAlinhado(dados: []align(16) u8) void {
std.debug.print("Dados alinhados a 16 bytes: {} bytes\n", .{dados.len});
}
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
// Alocar com alinhamento específico
const dados = try gpa.allocator().alignedAlloc(u8, 16, 64);
defer gpa.allocator().free(dados);
@memset(dados, 0);
processarAlinhado(dados);
}
Casos de uso comuns
- Callbacks de C: Converter
*anyopaque(void*) para ponteiros tipados. - Serialização: Interpretar buffers de bytes como structs alinhadas.
- SIMD: Garantir alinhamento para instruções vetoriais.
- Memory-mapped I/O: Acessar registradores de hardware com alinhamento correto.
Verificação em runtime
Em modos Debug e ReleaseSafe, @alignCast insere uma verificação em runtime que causa panic se o ponteiro não estiver alinhado corretamente:
thread 0 panic: incorrect alignment
Em ReleaseFast e ReleaseSmall, a verificação é removida por performance — passar um ponteiro mal alinhado se torna undefined behavior. Por isso, @alignCast é seguro em desenvolvimento mas exige cuidado em produção.
Equivalente em C
Em C não existe verificação equivalente — cast de ponteiro sempre compila sem aviso:
void *p = malloc(1);
uint32_t *q = (uint32_t *)p; // mal alinhado, UB silencioso
Em Zig, o mesmo cenário causa panic imediato em modo debug, facilitando muito a detecção de bugs de alinhamento.
Quando @alignCast é necessário
O compilador exige @alignCast quando o alinhamento do ponteiro de destino é maior que o do ponteiro de origem. Alguns casos comuns:
| De | Para | Necessário? |
|---|---|---|
*anyopaque (align 1) | *u32 (align 4) | Sim |
[*]u8 (align 1) | *Struct (align 8) | Sim |
*u32 (align 4) | *u8 (align 1) | Não |
*u64 (align 8) | *u32 (align 4) | Não |
Combinando com @ptrCast
Na prática, @alignCast quase sempre é usado junto com @ptrCast. A ordem correta é @ptrCast(@alignCast(ptr)):
// Correto: @alignCast ajusta o alinhamento, @ptrCast muda o tipo
const p: *MinhaStruct = @ptrCast(@alignCast(ptr_opaco));
// O compilador também aceita separados em contexto com tipo anotado:
const p2: *MinhaStruct = @alignCast(ptr_opaco);
// Zig infere o @ptrCast automaticamente quando necessário
Erros comuns
Esquecer o @alignCast ao converter de *anyopaque: O compilador emitirá um erro pedindo o cast explícito de alinhamento. Esse erro em tempo de compilação é preferível a um crash silencioso.
Passar memória não alinhada: Alocar com allocator.alloc(u8, n) e tentar fazer @alignCast para um tipo com alinhamento 16 pode falhar se o allocator não garantir esse alinhamento. Use allocator.alignedAlloc para esses casos.
Perguntas Frequentes
Por que o Zig não faz @alignCast automaticamente ao fazer @ptrCast?
Por segurança explícita. O Zig quer que o programador reconheça que está fazendo uma suposição sobre alinhamento. O @alignCast documenta essa intenção no código.
Posso usar @alignCast com slices?
Sim. @alignCast funciona com []T, [*]T, [*:0]T e outros tipos de ponteiro, não apenas *T.
Builtins relacionados
- @ptrCast — Conversão entre tipos de ponteiro
- @alignOf — Consultar alinhamento de um tipo
- @constCast — Remover qualificador const
- @as — Conversão de tipo segura