¿Cómo usar @sizeOf con enums?

¿Cómo usar @sizeOf con enums?

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 desde 0.

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 struct con bool)

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 llamado Day con valores por defecto 0 a 6.
  • En pub fn main() void { ... } se define la función principal que ejecutará el programa.
  • Dentro de main, std.debug.print imprime 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 devuelve 1 en este caso, porque el valor máximo (6) cabe en un u8.

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 ErrorCode especifica explícitamente u8 como tipo subyacente.
  • La impresión mostrará 1, porque u8 ocupa 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 u8 pero dentro de u16, el tamaño aumentará automáticamente.
  • Los enums que solo representan flags suelen definirse como packed struct con campos bool para evitar sobrecarga de memoria.
  • Para forzar un tamaño específico, se recomienda declarar el tipo subyacente explícitamente.
  • Al usar @sizeOf con enum en 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:

Comments

No comments yet. Why don’t you start the discussion?

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *