@intFromPtr em Zig
O @intFromPtr converte um ponteiro para seu valor numérico de endereço de memória, representado como um usize. Esse builtin é essencial para programação de baixo nível, incluindo desenvolvimento de sistemas operacionais, drivers e alocadores de memória personalizados.
Sintaxe
@intFromPtr(ptr: anytype) usize
O que faz
O @intFromPtr extrai o endereço numérico de memória contido em um ponteiro e o retorna como um valor usize. Essa operação é o inverso de @ptrFromInt. O valor retornado representa o endereço de memória virtual onde o dado apontado reside.
Esta é uma operação de baixo nível que deve ser usada com cuidado, pois trabalhar diretamente com endereços de memória pode facilmente levar a comportamento indefinido se usado incorretamente.
Parâmetros
- ptr (
anytype): Um ponteiro de qualquer tipo. Pode ser um ponteiro simples (*T), um ponteiro para muitos ([*]T), um slice ([]T) — neste caso, retorna o endereço do início — ou qualquer outra variante de ponteiro.
Valor de retorno
Retorna um usize contendo o endereço numérico de memória do ponteiro.
Exemplos práticos
Exemplo 1: Obtendo o endereço de uma variável
const std = @import("std");
test "endereço de variável" {
var valor: u32 = 42;
const ptr = &valor;
const endereco = @intFromPtr(ptr);
std.debug.print("Valor: {}\n", .{valor});
std.debug.print("Endereço: 0x{x}\n", .{endereco});
// O endereço é um número positivo diferente de zero
try std.testing.expect(endereco != 0);
// Converter de volta para ponteiro funciona
const ptr_recuperado: *u32 = @ptrFromInt(endereco);
try std.testing.expect(ptr_recuperado.* == 42);
}
Exemplo 2: Verificação de alinhamento
const std = @import("std");
fn estaAlinhado(ptr: anytype, comptime alinhamento: usize) bool {
const endereco = @intFromPtr(ptr);
return endereco % alinhamento == 0;
}
test "verificar alinhamento" {
var buffer: [64]u8 align(16) = undefined;
const ptr = &buffer;
// Buffer declarado com align(16) deve estar alinhado a 16 bytes
try std.testing.expect(estaAlinhado(ptr, 16));
try std.testing.expect(estaAlinhado(ptr, 8));
try std.testing.expect(estaAlinhado(ptr, 4));
}
Exemplo 3: Aritmética de ponteiros para alocador personalizado
const std = @import("std");
const AlocadorBump = struct {
buffer: []u8,
offset: usize,
fn init(buffer: []u8) AlocadorBump {
return .{ .buffer = buffer, .offset = 0 };
}
fn alocar(self: *AlocadorBump, tamanho: usize, comptime alinhamento: usize) ?[*]u8 {
// Calcular endereço alinhado usando aritmética de ponteiro
const ptr_atual = @intFromPtr(self.buffer.ptr) + self.offset;
const alinhado = (ptr_atual + alinhamento - 1) & ~(@as(usize, alinhamento) - 1);
const desperdicio = alinhado - ptr_atual;
const total = desperdicio + tamanho;
if (self.offset + total > self.buffer.len) return null;
self.offset += total;
return @ptrFromInt(alinhado);
}
};
test "alocador bump" {
var buffer: [1024]u8 = undefined;
var alocador = AlocadorBump.init(&buffer);
const ptr1 = alocador.alocar(32, 8);
try std.testing.expect(ptr1 != null);
try std.testing.expect(@intFromPtr(ptr1.?) % 8 == 0);
const ptr2 = alocador.alocar(64, 16);
try std.testing.expect(ptr2 != null);
try std.testing.expect(@intFromPtr(ptr2.?) % 16 == 0);
}
Casos de uso comuns
- Alocadores de memória personalizados: Calcular alinhamentos, offsets e tamanhos de blocos alocados.
- Depuração de memória: Imprimir endereços de ponteiros para investigar layout de memória.
- Verificação de alinhamento: Verificar se um ponteiro está corretamente alinhado para operações SIMD ou requisitos de hardware.
- Desenvolvimento de kernel/drivers: Trabalhar com endereços de memória mapeados em hardware.
- Hashing de ponteiros: Usar o endereço como chave em tabelas hash.
Builtins relacionados
- @ptrFromInt — Operação inversa: converte inteiro para ponteiro
- @ptrCast — Conversão entre tipos de ponteiro
- @alignCast — Converte alinhamento de ponteiro
- @alignOf — Obtém o alinhamento de um tipo
- @sizeOf — Obtém o tamanho em bytes de um tipo