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 0x2007h: Los valores de retorno numéricos deben definirse como constantes de preprocesador o enums

Funciones, contratos y modularizacion (0x20XX)

Universidad Nacional de Río Negro

0x2007h: Los valores de retorno numéricos deben definirse como constantes de preprocesador o enums

Enunciado normativo

NO DEBEN aparecer números mágicos como valor de retorno o como código de comparación. Todo valor de retorno con significado propio DEBE expresarse mediante un enum o una constante simbólica con nombre de dominio.

¿Por qué existe esta regla?

El problema

return -1; no dice nada: ¿“no encontrado”, “error de apertura” o “argumento inválido”? Si el mismo -1 significa dos cosas en dos ramas, comparar contra -1 deja de verificar nada. Un nombre simbólico convierte el número en contrato: varias causas comparten un valor sin ambigüedad y un cambio de código se hace en un solo lugar.

Consecuencias de violarla

Tipo de consecuenciaEfecto concreto
Bug silenciosoComparar if (resultado == -1) confunde dos errores distintos.
MantenibilidadCambiar un código obliga a rastrear todos los literales.

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

C11 permite que las constantes de enumeración sean enteros con nombre (§6.4.4.4 y §6.7.2.2). La cátedra exige nombres de dominio porque el valor de retorno es la interfaz principal entre funciones; se complementa con 0x300Dh: Utilizá enum en lugar de ‘números mágicos’ para conjuntos de estados y valores constantes y con la nomenclatura de 0x0107h: Las macros #define deben nombrarse en MAYUSCULAS_SNAKE_CASE.

Alcance y excepciones

Cubre códigos de error, estados y banderas con significado. No alcanza a valores universales (0, 1), a centinelas locales evidentes ni a constantes de la biblioteca (EOF, EXIT_SUCCESS).

Ejemplos exhaustivos

❌ Contraejemplo 1 — Números mágicos en el retorno

int abrir_recurso(const char *ruta)
{
    if (ruta == NULL) {
        return -1;
    }
    FILE *f = fopen(ruta, "r");
    if (f == NULL) {
        return -1;
    }
    if (verificar(f) != 0) {
        return -2;
    }
    return 0;
}

-1 significa a la vez “puntero nulo” y “no se pudo abrir”; el llamador no puede distinguir la causa.

❌ Contraejemplo 2 — Comparación contra literales en el llamador

int estado = procesar(lote);

if (estado == 1) {
    printf("Pendiente\n");
} else if (estado == 2) {
    printf("Aprobado\n");
}

1 y 2 no están definidos; reordenar el enum de origen imprime la etiqueta equivocada sin que el compilador proteste.

✅ Ejemplo conforme 1 — Enum de estados

enum estado_pedido_t {
    ESTADO_PENDIENTE,
    ESTADO_APROBADO,
    ESTADO_RECHAZADO
};

enum estado_pedido_t procesar(const struct lote_t *lote)
{
    if (lote == NULL) {
        return ESTADO_RECHAZADO;
    }
    if (lote->cajas == 0) {
        return ESTADO_PENDIENTE;
    }
    return ESTADO_APROBADO;
}

El enum da nombre a cada estado y el llamador compara contra símbolos, no contra números.

✅ Ejemplo conforme 2 — Constantes de error con nombre de dominio

#define OK                 0
#define ERROR_PUNTERO_NULO (-1)
#define ERROR_APERTURA     (-2)

int guardar(const char *ruta, const char *texto)
{
    if (ruta == NULL || texto == NULL) {
        return ERROR_PUNTERO_NULO;
    }
    FILE *f = fopen(ruta, "w");
    if (f == NULL) {
        return ERROR_APERTURA;
    }
    int escritos = fputs(texto, f);
    fclose(f);
    return escritos == EOF ? ERROR_APERTURA : OK;
}

Cada valor tiene nombre y significado único; se documenta en el @returns.

⚠️ Casos límite

Cómo detectarla

HerramientaComandoSeñal
gaffgaff check archivo.cLiterales numéricos en return o en comparaciones.
grepgrep -nE "return -?[0-9]+;" archivo.cRetornos con enteros desnudos.

Checklist de autocontrol

Reglas relacionadas