Regla 0x2007h: Los valores de retorno numéricos deben definirse como constantes de preprocesador o enums
Funciones, contratos y modularizacion (0x20XX)
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
enumo 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 consecuencia | Efecto concreto |
|---|---|
| Bug silencioso | Comparar if (resultado == -1) confunde dos errores distintos. |
| Mantenibilidad | Cambiar 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¶
boolfrente a código de error: usáboolcon dos resultados yenumcuando la causa importa.Retorno
NULL: es el código de error propio de los punteros y se compara conNULL, no con un entero (0x3008h: Los punteros nulos deben ser inicializados y comparados con NULL, no con 0).
Cómo detectarla¶
| Herramienta | Comando | Señal |
|---|---|---|
gaff | gaff check archivo.c | Literales numéricos en return o en comparaciones. |
grep | grep -nE "return -?[0-9]+;" archivo.c | Retornos con enteros desnudos. |
Checklist de autocontrol¶
¿Todos mis códigos de retorno tienen nombre simbólico?
¿El llamador compara contra el símbolo y no contra el número?
Reglas relacionadas¶
0x300Dh: Utilizá enum en lugar de ‘números mágicos’ para conjuntos de estados y valores constantes —
enumes el mecanismo preferido para conjuntos de estados.0x2003h: Todas las funciones deben incluir documentación completa y estructurada — el contrato documenta cada valor simbólico.