Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Regla 0x300Dh: Utilizá enum en lugar de 'números mágicos' para conjuntos de estados y valores constantes

Memoria, punteros y tipos (0x30XX)

Universidad Nacional de Río Negro

0x300Dh: Utilizá enum en lugar de ‘números mágicos’ para conjuntos de estados y valores constantes

Enunciado normativo

Los conjuntos de estados y de valores constantes relacionados DEBEN declararse con enum (o con constantes simbólicas con nombre) y NO DEBEN aparecer como literales numéricos dispersos en el código.

¿Por qué existe esta regla?

El problema

Un literal como if (estado == 2) no dice qué representa 2: el significado vive sólo en la cabeza del autor y quien escribe puede confundirlo con el 3. enum introduce un conjunto de constantes con nombre junto al tipo, y así el compilador, el depurador y el lector comparten la misma semántica.

Consecuencias de violarla

Tipo de consecuenciaEfecto concreto
Bug lógicoDos estados se confunden porque 1 y 2 son intercambiables a la vista.
MantenibilidadInsertar un estado intermedio obliga a renumerar todos los usos.
DepuraciónEl depurador muestra 2 en lugar de ESTADO_LISTO.

Fundamento en el estándar y en la cátedra

C11 §6.7.2.2 define enum como un conjunto de constantes enteras con nombre. La cátedra lo adopta para todo grupo de valores mutuamente excluyentes y lo prefiere sobre #define porque agrupa los valores y les da un tipo.

Alcance y excepciones

Aplica a estados, modos, códigos de error y conjuntos de valores relacionados. No aplica a constantes de dominio aisladas (por ejemplo una longitud máxima), donde corresponde un #define o una const conforme a 0x0103h: Las constantes (const o #define) deben nombrarse en MAYUSCULAS_SNAKE_CASE.

Ejemplos exhaustivos

❌ Contraejemplo 1 — Comparación contra un literal

if (estado == 2)
{
    reiniciar();
}

Por qué falla: no se sabe qué es 2. Si el conjunto de estados cambia, el significado se pierde y la comparación puede pasar a referirse a otro estado. El nombre del estado debería estar en el código.

❌ Contraejemplo 2 — Constantes relacionadas definidas por separado

#define ESTADO_NUEVO 0
#define ESTADO_LISTO 1
#define ESTADO_ERROR -1
void avanzar(int estado)
{
    if (estado == ESTADO_LISTO)
    {
        siguiente_paso();
    }
}

Por qué falla: los valores se declaran por separado, sin un tipo que los agrupe. avanzar acepta cualquier int, incluidos valores ajenos al conjunto, y el compilador no puede advertirlo.

✅ Ejemplo conforme 1 — enum con tipo propio

typedef enum estado
{
    ESTADO_NUEVO,
    ESTADO_LISTO,
    ESTADO_ERROR
} estado_t;
void avanzar(estado_t estado)
{
    if (estado == ESTADO_LISTO)
    {
        siguiente_paso();
    }
}

El conjunto y su tipo se declaran juntos. El lector ve el nombre del estado, el depurador también, y la firma comunica que sólo se aceptan valores del conjunto. El alias respeta 0x3004h: Utilizá typedef para definir tipos de estructuras con el sufijo _t.

✅ Ejemplo conforme 2 — enum para índices simbólicos

typedef enum campo
{
    CAMPO_NOMBRE = 0,
    CAMPO_EDAD,
    CAMPO_CIUDAD,
    CAMPO_CANTIDAD
} campo_t;
char *etiquetas[CAMPO_CANTIDAD];
etiquetas[CAMPO_EDAD] = "Edad";

CAMPO_CANTIDAD cierra el conjunto y expresa la dimensión del arreglo, evitando un literal de tamaño. Los índices se leen con nombre y el arreglo no puede desincronizarse sin advertirlo. Se refuerza con 0x010Fh: Prohibición de constantes numéricas mágicas en índices de arreglos.

⚠️ Casos límite

Cómo detectarla

HerramientaComandoSeñal
gaffgaff check archivo.cComparación de estado contra literal numérico.
gcc / clanggcc -Wall -Wextra -std=c11 -Wswitch-enum ...case faltante en switch sobre enum.
Revisión manualLiterales repetidos que representan el mismo estado.

Checklist de autocontrol

Reglas relacionadas

Antipatrón: Número mágico literal en condición lógica

Síntoma en el código del estudiante

Las decisiones de dominio se escriben con literales sueltos:

if (estado == 404) {
    /* ... */
} else if (estado == 500) {
    /* ... */
}

El lector no puede saber qué significa 404 ni 500 sin acudir al enunciado. Lo mismo ocurre con 0, 1, 2 usados como modos de un TAD.

Diagnóstico

Mecanismo del defecto

Un literal numérico no tiene nombre ni tipo semántico. El compilador solo ve un int; no puede verificar que el valor pertenezca al conjunto válido de estados. Cuando el conjunto cambia (se agrega un estado, se reordena), hay que cazar todos los literales repetidos a mano y cada omisión se convierte en un bug lógico silencioso.

El mismo problema es más grave al pasar estos valores como argumentos: una firma void configurar(int modo) acepta cualquier entero, incluidos los que no tienen sentido. Un enum restringe el dominio y autodocumenta el contrato.

Consecuencia observable

Fundamento en el estándar C11

Corrección idiomática

❌ Código con el antipatrón
int procesar(int estado)
{
    if (estado == 1) {
        return 0;
    } else if (estado == 2) {
        return 1;
    }
    return -1;
}
✅ Código refactorizado — enum con nombre
typedef enum {
    ESTADO_NUEVO = 0,
    ESTADO_EN_PROCESO = 1,
    ESTADO_TERMINADO = 2
} estado_t;

int procesar(estado_t estado)
{
    switch (estado) {
    case ESTADO_NUEVO:
        return 0;
    case ESTADO_EN_PROCESO:
        return 1;
    case ESTADO_TERMINADO:
        return 2;
    default:
        return -1;
    }
}
✅ Alternativa — constantes #define para valores externos
#define HTTP_NOT_FOUND 404
#define HTTP_SERVER_ERROR 500

if (codigo == HTTP_NOT_FOUND) {
    /* ... */
}

enum es preferible cuando los valores forman un conjunto cerrado y relacionado; #define sirve para constantes aisladas.

⚠️ Casos límite

Errores típicos al compilar o ejecutar

# El compilador no detecta un valor fuera de dominio:
$ ./programa
# estado = 7 entra por ninguna rama y devuelve -1 silenciosamente

$ gcc -Wall -Wextra -std=c11 -Wswitch programa.c
# con enum y switch sin default útil, avisa si falta un caso enumerado

Checklist de verificación

Reglas relacionadas