Regla 0x1001h: Todas las estructuras de control deben utilizar llaves
Estructuras de control y flujo (0x10XX)
0x1001h: Todas las estructuras de control deben utilizar llaves¶
Enunciado normativo¶
DEBE delimitarse con llaves
{ }el cuerpo de toda estructura de control (if,else,for,while,do-whileyswitch), aunque contenga una única sentencia.
Escribir el cuerpo sin llaves, aunque sea sintácticamente válido, queda prohibido en todas las entregas de la cátedra.
¿Por qué existe esta regla?¶
El problema¶
En C una estructura de control gobierna exactamente una sentencia, que
puede ser un bloque { ... } o una sentencia suelta. Cuando se omite la llave,
agregar después una segunda instrucción “dentro” del if es un cambio que el
compilador acepta en silencio: la instrucción nueva queda fuera del control.
El error no se manifiesta al escribir, sino al leer y al mantener.
La llave convierte la intención en sintaxis. Con llaves, el cuerpo es un bloque explícito y cualquier sentencia agregada entre ellas pertenece al control por construcción, no por posición.
Consecuencias de violarla¶
| Tipo de consecuencia | Efecto concreto |
|---|---|
| Bug lógico | Una sentencia nueva se agrega fuera del if/for y se ejecuta siempre. |
| Ambigüedad sintáctica | En if anidados, el else se asocia al if más próximo, no al que se pretendía. |
| Sentencia nula | Un ; accidental tras la condición desacopla el bloque del control. |
| Mantenibilidad | El diff de una corrección futura puede invertir el sentido del código sin aviso. |
Fundamento en el estándar y en la cátedra¶
El estándar ISO/IEC 9899:2011 §6.8.4 define que el cuerpo de un if es una
statement, que puede ser compuesta (bloque) o simple. La cátedra adopta la
forma compuesta obligatoria como defensa barata contra los defectos anteriores;
complementa a 0x0007h: Las llaves deben ubicarse en líneas independientes según el estilo Allman, que fija el estilo de llaves Allman.
Alcance y excepciones¶
Aplica a toda estructura de control en código de estudiante, sin importar la
cantidad de sentencias del cuerpo. No hay excepción por “una sola línea”. Los
cuerpos vacíos intencionales (if (x); o while (getchar() != '\n');) siguen
prohibidos por 0x100Ah: Prohibición de estructuras de control con cuerpo vacío (if (...);); si el cuerpo está vacío, la llave no lo salva.
Ejemplos exhaustivos¶
❌ Contraejemplo 1 — if sin llaves con sentencia agregada después¶
if (temperatura > 100)
apagar_horno();
registrar_evento("apagado");Por qué falla: registrar_evento no está dentro del if; se ejecuta siempre,
incluso con el horno frío. La indentación engaña, la semántica no.
❌ Contraejemplo 2 — else colgado en anidamiento sin llaves¶
if (usuario_valido)
if (clave_correcta)
permitir_acceso();
else
denegar_acceso();Por qué falla: el else pertenece al if (clave_correcta), no al if (usuario_valido). Un usuario inválido nunca ejecuta denegar_acceso().
✅ Ejemplo conforme 1 — llaves en cada nivel¶
if (usuario_valido)
{
if (clave_correcta)
{
permitir_acceso();
}
else
{
denegar_acceso();
}
}El bloque exterior deja explícito a qué if pertenece cada else, y agregar
sentencias dentro de cualquier rama no cambia el control.
✅ Ejemplo conforme 2 — llaves con una sola sentencia¶
for (size_t i = 0; i < cantidad; i++)
{
total += valores[i];
}Aunque el cuerpo tenga una única línea, la llave documenta el alcance y evita
que un if de depuración agregado mañana quede fuera del lazo.
⚠️ Casos límite¶
ifde una línea real: si el cuerpo es genuinamente trivial y estable, igual se escriben llaves; el costo es de dos líneas.switch: las llaves delimitan el bloque, pero cadacasesigue gobernando hasta elbreak(ver 0x1008h: Toda instrucción switch debe incluir un caso default).Macros que expanden a bloques: usar
do { ... } while (0)(ver 0x500Ah: Protección obligatoria de parámetros en macros funcionales mediante paréntesis); omitir llaves rompe la macro al usarla en unif.
Cómo detectarla¶
| Herramienta | Comando | Señal |
|---|---|---|
gaff | gaff check archivo.c | Regla 0x1001h: cuerpo sin llaves. |
gcc | gcc -Wall -Wextra -Wmisleading-indentation -Wdangling-else | warning: this 'else' clause does not guard... |
| Revisión visual | — | Condición seguida de sentencia indentada sin {. |
Checklist de autocontrol¶
¿Todo
if,else,for,while,do-whileyswitchtiene llaves?¿Agregué una sentencia al cuerpo y verifiqué que quedó dentro del control?
¿Hay un
;inmediatamente después de alguna condición? (ver 0x100Ah: Prohibición de estructuras de control con cuerpo vacío (if (...);))¿Los
elseanidados quedan sin ambigüedad posible?
Reglas relacionadas¶
0x100Ah: Prohibición de estructuras de control con cuerpo vacío (if (...);) — complementa: prohíbe el cuerpo nulo que la llave no cubre.
0x0007h: Las llaves deben ubicarse en líneas independientes según el estilo Allman — refuerza: define el estilo Allman de las llaves.
0x100Eh: Delimitación obligatoria con bloque de llaves en lazos do-while — complementa: exige llaves también en
do-while.
Antipatrón: Punto y coma accidental tras condición de control¶
Síntoma en el código del estudiante¶
Después de la condición de un if, while o for aparece un ; pegado al
paréntesis, y a continuación un bloque entre llaves que se pretende parte del
control:
if (x > 0);
{
hacer_algo();
}La indentación sugiere que el bloque pertenece al if, pero el ; ya cerró el
cuerpo con una sentencia vacía.
Diagnóstico¶
Mecanismo del defecto¶
En C, el ; es una sentencia nula válida (ISO/IEC 9899:2011 §6.8.3). El
compilador la toma como el cuerpo del if: la condición se evalúa y, si es
verdadera, ejecuta “nada”. El bloque siguiente es una sentencia compuesta
independiente que se ejecuta siempre, haya o no cumplido la condición.
Consecuencia observable¶
El programa compila sin errores y el bloque se ejecuta incondicionalmente. Si el
if protegía una validación o una inicialización, el efecto es que ya no
protege nada. En el caso de while (cond);, el lazo gira para siempre porque
su cuerpo vacío no modifica el estado. No hay ningún warning por defecto.
Fundamento en el estándar C11¶
ISO/IEC 9899:2011 §6.8.3 define la sentencia nula, y §6.8.4.1 asocia el cuerpo
del if a la sentencia inmediatamente siguiente. La cátedra exige llaves en
toda estructura de control (regla 0x1001h), lo que hace visible este error y
lo vuelve imposible de introducir sin que salte a la vista.
Corrección idiomática¶
❌ Código con el antipatrón¶
if (x > 0);
{
hacer_algo();
}✅ Código refactorizado¶
if (x > 0)
{
hacer_algo();
}Eliminar el ; restituye el bloque como cuerpo del if; la llave y el estilo
Allman dejan el control explícito.
Errores típicos al compilar o ejecutar¶
Con el antipatrón: el programa compila sin avisos y ejecuta hacer_algo()
aunque x <= 0. No hay mensaje de error que delate la causa.
Al compilar con -Wempty-body:
warning: suggest braces around empty body in an 'if' statement [-Wempty-body]Checklist de verificación¶
¿Alguna condición termina en
;?¿El bloque siguiente se ejecuta condicionalmente como se pretende?
¿La llave de apertura está en la línea siguiente según Allman?
¿Compilé con
-Wempty-bodypara detectar cuerpos vacíos?
Reglas relacionadas¶
0x1001h: Todas las estructuras de control deben utilizar llaves — norma este antipatrón: llaves obligatorias en todo control.
0x100Ah: Prohibición de estructuras de control con cuerpo vacío (if (...);) — la regla hermana que prohíbe el cuerpo nulo.
0x0007h: Las llaves deben ubicarse en líneas independientes según el estilo Allman — estilo Allman para ubicar la llave de apertura.
Antipatrón: Ambigüedad sintáctica por omisión de llaves en condicional anidado (Dangling Else)¶
Síntoma en el código del estudiante¶
Un if interno sin llaves convive con un else cuya indentación (o la
intención del autor) sugiere que pertenece al if externo:
if (a)
if (b)
foo();
else
bar();Diagnóstico¶
Mecanismo del defecto¶
La gramática de C asocia cada else con el if no emparejado más cercano
(ISO/IEC 9899:2011 §6.8.4.1). Por lo tanto else pertenece a if (b), no a
if (a). La indentación no tiene valor sintáctico: el compilador ignora los
espacios y aplica la regla del “if colgado”.
Consecuencia observable¶
Cuando a es falso, bar() no se ejecuta, aunque el autor esperaba lo
contrario. Cuando a es verdadero y b falso, sí se ejecuta. El resultado es
un bug lógico que depende de la combinación de condiciones, sin ningún error de
compilación ni advertencia por defecto.
Fundamento en el estándar C11¶
ISO/IEC 9899:2011 §6.8.4.1 establece la asociación del else con el if más
próximo. La cátedra elimina la ambigüedad con llaves obligatorias en cada nivel
condicional (regla 0x1001h), de modo que la estructura escrita coincide con la
intención sin depender de la indentación.
Corrección idiomática¶
❌ Código con el antipatrón¶
if (a)
if (b)
foo();
else
bar();✅ Código refactorizado¶
if (a)
{
if (b)
{
foo();
}
}
else
{
bar();
}Las llaves fijan a qué if pertenece cada else: ahora el else pertenece al
if (a) de forma explícita y bar() se ejecuta cuando a es falso.
Errores típicos al compilar o ejecutar¶
Con -Wdangling-else (incluida en -Wall):
warning: this 'else' clause does not guard... [-Wdangling-else]
note: ...this 'if' clause
Sin la advertencia, el comportamiento es el del 'else' más cercano;
bar() no se ejecuta cuando a es falso.Checklist de verificación¶
¿Hay
ifanidados sin llaves?¿A qué
ifpertenece realmente cadaelse?¿Las llaves hacen explícita la intención?
¿Compilé con
-Wdangling-elseo-Wall?
Reglas relacionadas¶
0x1001h: Todas las estructuras de control deben utilizar llaves — norma este antipatrón: llaves en toda estructura de control.
0x100Ah: Prohibición de estructuras de control con cuerpo vacío (if (...);) — otro defecto sintáctico silencioso en condiciones.
0x0007h: Las llaves deben ubicarse en líneas independientes según el estilo Allman — estilo Allman que hace visible el anidamiento.