En Zig, la función compile‑time @sizeOf(T) devuelve el tamaño en bytes del tipo T. Cuando T es un enum, el resultado depende de cómo el compilador haya seleccionado el underlying type del enumerado. Comprender este comportamiento es fundamental para diseñar estructuras de datos compactas o para interactuar con API de bajo nivel.
Comprendiendo @sizeOf
@sizeOf no se evalúa en tiempo de ejecución; su valor es conocido en la fase de compilación. Esto permite optimizaciones, generación de estructuras fijas y verificaciones estáticas. Cuando aplicamos @sizeOf a un enum, Zig necesita decidir cuántos bits se requieren para almacenar todos los valores posibles.
Reglas de selección del tipo subyacente en enums
- Si el enum tiene un valor explícito de
:uN(por ejemplo:u8), ese tipo será usado. - Si no se especifica, Zig elige el tipo subyacente más pequeño que pueda contener todos los valores, entre
u8, u16, u32, u64, u128. - En caso de que el enum sea
enum { ... };sin valores numéricos asignados, Zig asigna automáticamente valores consecutivos comenzando desde0.
Enums en Zig
Un enum en Zig es una colección de etiquetas que pueden asociarse a valores numéricos. Por defecto, Zig asigna 0 al primer elemento, 1 al segundo y así sucesivamente, a menos que se especifique lo contrario.
// Ejemplo de enum sin valores explícitos
const Color = enum {
Red, // 0
Green, // 1
Blue, // 2
};
Si queremos controlar el tipo subyacente o los valores, podemos hacerlo de la siguiente manera:
// Enum con tipo explícito y valores definidos
const Status = enum(u8) {
Ok = 0, // 0
Warning = 1, // 1
Error = 2, // 2
Critical = 255, // 255
};
Listas de enumeraciones comunes
- Representación de colores (RGB, RGBA)
- Estados de una máquina de estados
- Tipo de mensajes en un protocolo
- Flags de configuración (usando
packed structconbool)
Uso de @sizeOf con enums
Cuando usamos @sizeOf(Color), Zig calcula el tamaño del tipo subyacente elegido por el compilador. Si el enum no tiene un tipo explícito y sus valores máximos se ajustan a u8, el resultado será 1 byte. Si el máximo necesita u16, entonces el resultado será 2 bytes.
Ejemplo 1: Enum sin tipo explícito
const std = @import("std");
// Definimos un enum simple
const Day = enum {
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
Sunday,
};
pub fn main() void {
// Imprimimos el tamaño del enum en bytes
std.debug.print("Tamaño de Day: {d} bytes\n", .{@sizeOf(Day)});
}
Comentario línea por línea:
const std = @import("std");importa el paquete estándar de Zig.const Day = enum { ... };declara un enum llamadoDaycon valores por defecto0a6.- En
pub fn main() void { ... }se define la función principal que ejecutará el programa. - Dentro de
main,std.debug.printimprime en consola. El primer argumento es el formato de cadena, y{d}indica que el valor será un entero decimal. .{@sizeOf(Day)}es la forma de pasar el tamaño calculado como argumento. @sizeOf se evalúa en tiempo de compilación y devuelve1en este caso, porque el valor máximo (6) cabe en unu8.
Ejemplo 2: Enum con tipo explícito
const std = @import("std");
const ErrorCode = enum(u8) {
Success = 0,
NotFound = 1,
PermissionDenied = 2,
OutOfMemory = 3,
};
pub fn main() void {
std.debug.print("Tamaño de ErrorCode: {d} bytes\n", .{@sizeOf(ErrorCode)});
}
- El enum
ErrorCodeespecifica explícitamenteu8como tipo subyacente. - La impresión mostrará
1, porqueu8ocupa un byte.
Ejemplo 3: Enum sin valores y con un máximo grande
const std = @import("std");
const LargeEnum = enum {
A, // 0
B, // 1
C, // 2
// ...
// Supongamos que añadimos 300 valores en total
// para ilustrar cómo @sizeOf crecerá
// Los últimos valores no se muestran aquí por brevedad
};
pub fn main() void {
const size = @sizeOf(LargeEnum);
std.debug.print("Tamaño de LargeEnum: {d} bytes\n", .{size});
}
En este caso, si LargeEnum tiene 300 miembros, el valor máximo será 299, que cabe en u16 (hasta 65535). Por lo tanto, @sizeOf(LargeEnum) devolverá 2.
Consideraciones especiales
- Si el enum incluye valores fuera del rango de
u8pero dentro deu16, el tamaño aumentará automáticamente. - Los enums que solo representan flags suelen definirse como
packed structcon camposboolpara evitar sobrecarga de memoria. - Para forzar un tamaño específico, se recomienda declarar el tipo subyacente explícitamente.
- Al usar
@sizeOfconenumen estructuras (struct), el empaquetado de la estructura puede afectar el alineamiento, pero el tamaño del enum se mantiene igual.
Ejemplo avanzado: Enum de flags con @sizeOf
Para crear un conjunto de banderas que se empaqueten en un solo byte, definimos un packed struct con campos bool. Luego usamos @sizeOf para comprobar el resultado.
const std = @import("std");
// Definimos flags de manera explícita
const Flags = packed struct {
isAdmin:
