wandres.dev
ESPECIALISTA · Enums y typedef

Enums y typedef

Enumeraciones con tipo subyacente fijo (novedad de C23), el arte de typedef para nombrar tipos, y los tipos opacos que ocultan implementación tras una API.

⏱ 12 min

Nombrar bien los tipos es diseño, no cosmética. Los enums dan nombres a conjuntos de valores; typedef crea alias que aclaran la intención y habilitan la encapsulación. Con C23, los enums además ganan control sobre su representación en memoria.

🎯 Al terminar esta lección sabrás
  • Enums y su valor numérico.
  • Enums con tipo subyacente fijo (C23).
  • typedef para claridad y abstracción.
  • Tipos opacos: ocultar la implementación.

Enums

Un enum da nombres a constantes enteras relacionadas:

enum Estado {
    INACTIVO,        // 0
    CARGANDO,        // 1
    LISTO,           // 2
    ERROR = 10,      // puedes fijar valores
    ABORTADO         // 11 (sigue desde el anterior)
};

enum Estado s = LISTO;

Usa enums en vez de “números mágicos” (if (s == 2)): if (s == LISTO) se lee solo y el compilador te ayuda con los switch exhaustivos.

Enums con tipo fijo (C23)

Antes, el tipo entero que respaldaba un enum lo elegía el compilador, lo que causaba problemas de tamaño y ABI. C23 te deja fijarlo:

enum Color : unsigned char {   // C23: respaldado por unsigned char (1 byte)
    ROJO, VERDE, AZUL
};
Por qué el tipo fijo importa en sistemas

Sin tipo fijo, el tamaño de un enum era impredecible entre compiladores y plataformas — un problema real cuando ese enum forma parte de un formato binario, un protocolo de red o una struct compartida entre módulos compilados por separado. Fijar : unsigned char o : uint32_t garantiza el tamaño y el layout exactos, haciendo el enum seguro para serializar y para cruzar fronteras de ABI (nivel 21). Es otro ejemplo del patrón de C23: darte control explícito donde antes había ambigüedad de implementación.

typedef: alias de tipos

typedef crea un nombre nuevo para un tipo existente. Dos usos principales:

// 1) claridad: nombres con significado
typedef uint32_t Id;
typedef struct Punto Punto;      // usar 'Punto' en vez de 'struct Punto'

// 2) simplificar tipos complejos (punteros a función)
typedef int (*Operacion)(int, int);
Operacion op = sumar;            // mucho más legible
💡
typedef con moderación

typedef aclara, pero también puede ocultar. Un typedef sobre un puntero (typedef struct X *XPtr) esconde que hay una indirección, lo que confunde sobre la propiedad y la vida del objeto. La convención sensata: usa typedef para structs (evita repetir struct), para punteros a función (que son ilegibles sin él), y para tipos opacos (abajo); pero no escondas punteros normales tras un alias. Que el lector vea el * cuando lo hay.

Tipos opacos: encapsulación en C

El patrón más potente que habilita typedef: exponer un tipo en tu header sin revelar su contenido. El usuario recibe un puntero opaco y solo puede tocarlo a través de tu API.

// archivo.h (lo que ve el usuario)
typedef struct Conexion Conexion;   // declaración adelantada, sin campos
Conexion *conexion_abrir(const char *host);
void      conexion_cerrar(Conexion *c);
int       conexion_enviar(Conexion *c, const char *msg);

// archivo.c (privado)
struct Conexion {                    // la definición real, oculta
    int socket;
    char buffer[4096];
    // …
};
El tipo opaco es la clase de C

Este patrón es cómo C logra encapsulación de verdad — el equivalente a los campos privados de una clase. El usuario de tu biblioteca recibe un Conexion * que puede pasar por ahí, pero no puede acceder a sus campos ni depende de su tamaño: solo existe tu API pública. Esto te da libertad total para cambiar la implementación (añadir campos, reorganizar) sin romper a nadie, y es la base de una ABI estable (nivel 21). FILE * de la librería estándar es exactamente esto: nunca has visto qué hay dentro de un FILE, y no lo necesitas. Diseñar tus módulos con tipos opacos es programación de sistemas madura.

⚔️ Nombra y encapsula
  1. Define un enum de estados y úsalo en un switch (con -Wall para el chequeo exhaustivo).
  2. Crea un enum C23 con tipo subyacente fijo y comprueba su sizeof.
  3. Usa typedef para un puntero a función y simplifica una declaración.
  4. Diseña un tipo opaco: header con la API, .c con la struct oculta. El usuario nunca ve los campos.