Regla 0x1015h: Limitá la profundidad de anidación a tres niveles
Estructuras de control y flujo (0x10XX)
0x1015h: Limitá la profundidad de anidación a tres niveles¶
Enunciado normativo¶
NO DEBE superarse una profundidad de anidación de tres niveles (una función más dos bloques de control anidados). Cuando un cuarto nivel aparece, DEBE extraerse una función, invertirse la condición o consolidarse el bloque.
¿Por qué existe esta regla?¶
El problema¶
Cada nivel de anidación agrega una condición que el lector debe tener activa
en la memoria mientras analiza el cuerpo interno. Con cuatro o cinco niveles,
la cláusula else de más arriba queda a decenas de líneas de distancia y se
vuelve imposible saber a qué if responde cada }.
La anidación profunda también es el síntoma típico de mezclar varias responsabilidades en un mismo bloque (ver 0x2014h: Cada función debe caber en una sola idea y en 25 líneas).
Consecuencias de violarla¶
| Tipo de consecuencia | Efecto concreto |
|---|---|
| Legibilidad | El “camino feliz” queda enterrado al final de una pirámide. |
| Errores lógicos | Un else mal ubicado o una llave mal cerrada pasan desapercibidos. |
| Testing | Cada camino requiere preparar todo el contexto de los niveles externos. |
| Mantenimiento | Agregar una condición obliga a reindentar medio archivo. |
Fundamento en la cátedra¶
Es la versión cuantificable de 0x2001h: Las funciones deben usar cláusulas de guarda y retornos anticipados para reducir la anidación profunda. El límite de tres niveles mantiene el cuerpo de la función dentro de una pantalla y hace visible el flujo incluso sin editor. Es además una métrica estándar de complejidad ciclomática.
Alcance y excepciones¶
Cuentan como niveles la función y cada if, for, while, do, switch o
bloque anidado. Un switch con case que a su vez tiene un if y un for
ya está en el límite. Se exceptúan tablas de inicialización anidadas
(struct dentro de struct) que no representan flujo de control.
Ejemplos exhaustivos¶
❌ Contraejemplo 1 — Pirámide de condiciones¶
int procesar(int v[], int n)
{
if (n > 0) {
for (int i = 0; i < n; i++) {
if (v[i] > 0) {
if (v[i] % 2 == 0) {
if (v[i] < limite) {
acumular(v[i]);
}
}
}
}
}
return total;
}Por qué falla: cuatro niveles dentro del for; el lector debe sostener
n > 0, la iteración, v[i] > 0 y la paridad para entender una sola línea.
La función hace demasiado (0x2014h: Cada función debe caber en una sola idea y en 25 líneas).
❌ Contraejemplo 2 — else colgante por exceso de niveles¶
if (a)
if (b)
if (c)
accion_a();
else
accion_b();Por qué falla: sin llaves, el else se asocia al if más cercano, no al que
el autor imaginó. Es el antipatrón dangling else (0x1001h), favorecido
por el anidamiento profundo y la falta de llaves (0x1001h: Todas las estructuras de control deben utilizar llaves).
✅ Ejemplo conforme 1 — Guardas y extracción¶
static bool es_par_positivo_menor(int x, int limite)
{
return x > 0 && x % 2 == 0 && x < limite;
}
int procesar(int v[], int n)
{
if (n <= 0) {
return 0;
}
for (int i = 0; i < n; i++) {
if (es_par_positivo_menor(v[i], limite)) {
acumular(v[i]);
}
}
return total;
}La condición múltiple se volvió una función con nombre; el lazo queda en dos
niveles y el camino de error (n <= 0) se atiende primero.
✅ Ejemplo conforme 2 — Invertir la condición¶
for (int i = 0; i < n; i++) {
if (v[i] <= 0) {
continue; /* descarta temprano */
}
procesar_positivo(v[i]);
}En lugar de anidar todo bajo if (v[i] > 0), se descarta el caso no deseado y
el resto queda al primer nivel. (Usar continue sólo donde la cátedra lo
permita; ver 0x1002h: Restringí el uso de break y continue; preferí lazos con bandera de control.)
⚠️ Casos límite¶
Un nivel más justificado: validar una fila y una columna de una matriz puede requerir tres niveles; más allá, extraer funciones.
Llaves ausentes: la profundidad visual engaña; el compilador anida igual aunque no haya llaves (0x1001h: Todas las estructuras de control deben utilizar llaves).
switchconcasesimples: no cuentan como anidación si elcaseno contiene otro bloque.
Cómo detectarla¶
| Herramienta | Comando | Señal |
|---|---|---|
| Revisión manual | — | Cuatro { consecutivos antes de una sentencia. |
giger | giger <archivo.c> | Métricas de complejidad por función. |
gcc | gcc -Wall -Wextra | -Wdangling-else advierte el else ambiguo. |
Checklist de autocontrol¶
¿Hay más de tres niveles en algún punto?
¿Puedo invertir una condición para salir antes?
¿Una de las condiciones internas merece una función con nombre?
¿Cada
}se corresponde inequívocamente con su{?
Reglas relacionadas¶
0x2001h: Las funciones deben usar cláusulas de guarda y retornos anticipados para reducir la anidación profunda — guardas y retornos anticipados.
0x2013h: Detector de bloques else superfluos tras sentencias terminales —
elsesuperfluo tras sentencia terminal.0x1001h: Todas las estructuras de control deben utilizar llaves — llaves obligatorias en toda estructura de control.
0x2014h: Cada función debe caber en una sola idea y en 25 líneas — función de una sola idea y tamaño acotado.