Layout de Memoria
En esta página
Por defecto, el compilador de Zolo puede reordenar los campos de un struct
(@repr(zolo)) para optimización interna. Cuando el orden y el alineamiento de
los campos son contratos — FFI con C/Rust, uniform buffers de GPU, protocolos
binarios — declaras el layout explícitamente con atributos:
@repr(C), @repr(packed), @repr(transparent), @align(N) y @size(N).
13-repr-align-size.zolo
// Feature: `@repr` / `@align` / `@size` — struct layout control
// Syntax:
// @repr(C | packed | transparent | zolo) on the struct
// @align(N) on a field (N must be a power of two)
// @size(N) on a field (forces minimum byte size)
// When to use: FFI with C/Rust plugins, GPU uniform buffers, binary
// protocols, layout-sensitive newtypes. Default `@repr(zolo)` lets
// the compiler reorder fields, which is unsuitable for binary stability.
//
// See `specs/repr-align-size.md` for the full specification.
// 1. @repr(C) — fields kept in declaration order, C-compatible layout.
@repr(C)
struct PacketHeader {
version: int,
flags: int,
length: int,
seq: int,
}
let hdr = PacketHeader { version: 1, flags: 0, length: 256, seq: 42 }
print("hdr.seq = {hdr.seq}")
// 2. @repr(packed) — no padding between fields.
// Useful for wire protocols where every byte matters.
@repr(packed)
struct WireFrame {
magic: int,
payload: int,
}
let w = WireFrame { magic: 0xCAFE, payload: 100 }
print("w.magic = {w.magic}")
// 3. @repr(transparent) — single-field newtype-like with identical
// binary layout to its inner field.
@repr(transparent)
struct Handle {
raw: int,
}
let h = Handle { raw: 42 }
print("h.raw = {h.raw}")
// 4. @align(N) on a field — force alignment under @repr(C).
// Useful for GPU uniform buffers where vec3 must be 16-byte aligned.
@repr(C)
struct CameraUniform {
@align(16) view_proj: float,
@align(16) view_pos: float,
@align(16) time: float,
}
let cam = CameraUniform { view_proj: 1.0, view_pos: 0.0, time: 0.5 }
print("cam.time = {cam.time}")
// 5. @size(N) on a field — pad to a minimum byte size.
@repr(C)
struct PaddedHeader {
@size(64) header: int,
payload: int,
}
let p = PaddedHeader { header: 1, payload: 2 }
print("p.payload = {p.payload}")
// 6. Errors caught at lint/check time (uncomment to see):
//
// @repr(unknown_policy)
// struct X { x: int }
// warning[unknown-repr]: unknown @repr policy `unknown_policy`
//
// @repr(transparent)
// struct Two { a: int, b: int }
// error[transparent-multi-field]: @repr(transparent) requires exactly one field
//
// @repr(C)
// struct Bad {
// @align(3) x: int // not a power of two
// @align(8192) y: int // exceeds 4096
// }
// error[align-not-power-of-two]
// error[align-too-large]
//
// struct DefaultRepr {
// @align(8) x: int // @align without @repr — meaningless
// }
// error[layout-in-default-repr]: `@align` requires an explicit
// `@repr(C|packed|transparent)` on the struct
Referencia rápida:
@repr(C)— campos en orden de declaración, compatible con C.@repr(packed)— sin padding entre campos (protocolo de red, archivo binario).@repr(transparent)— requiere exactamente un campo; layout idéntico al tipo interno.@align(N)— en un campo, fuerza el alineamiento aNbytes (potencia de dos, máx. 4096).@size(N)— en un campo, garantiza un tamaño mínimo deNbytes.
@align y @size requieren que el struct tenga un @repr explícito (no zolo).
El compilador emite un error en tiempo de verificación si la combinación es inválida.
Consulta también