Regla 0x1010h: Prohibición de comparaciones encadenadas no idiomáticas en C (a < b < c)
Estructuras de control y flujo (0x10XX)
0x1010h: Prohibición de comparaciones encadenadas no idiomáticas en C (a < b < c)¶
Enunciado normativo¶
NO DEBEN escribirse comparaciones encadenadas como
a < b < co0 <= x <= 10. Toda relación conjunta DEBE expresarse de forma explícita con el operador lógico&&:a < b && b < c.
¿Por qué existe esta regla?¶
El problema¶
En matemática, 0 <= x <= 10 significa que x está entre 0 y 10. En C esa
expresión se evalúa de izquierda a derecha: primero 0 <= x da 0 o 1, y
luego 1 <= 10 (o 0 <= 10) da siempre 1. La comparación es siempre
verdadera, independientemente de x.
El error es especialmente traicionero porque compila sin advertencias y el código parece correcto para quien piensa en notación matemática. El resultado es una condición que nunca filtra nada.
Consecuencias de violarla¶
| Tipo de consecuencia | Efecto concreto |
|---|---|
| Bug lógico | La condición es siempre verdadera y no filtra ningún valor. |
| Validación rota | Datos fuera de rango pasan como válidos. |
| Compilador silencioso | No hay warning; el error es puramente semántico. |
| Portabilidad | El resultado de (a < b) < c depende de la representación de bool. |
Fundamento en el estándar y en la cátedra¶
ISO/IEC 9899:2011 §6.5.8 define los operadores relacionales con resultado int
(0 o 1), y §6.5.13 el && de cortocircuito. La cátedra prohíbe el encadenado y
exige la forma explícita. gaff aplica el autofix. Se relaciona con
0x1013h: Detector de expresiones booleanas complejas sin paréntesis aclaratorios (paréntesis en expresiones mixtas) y con 0x1004h: Las condiciones complejas deben simplificarse o comentarse.
Alcance y excepciones¶
Aplica a cualquier encadenado de
<,>,<=,>=,==,!=.No hay excepción: aun
a == b == cdebe escribirsea == b && b == c.Comparar dos booleanos con
==(a == (b < c)) es válido y no es un encadenado.
Ejemplos exhaustivos¶
❌ Contraejemplo 1 — rango matemático¶
if (0 <= x <= 10)
{
aceptar(x);
}Por qué falla: 0 <= x da 0 o 1, y cualquiera de los dos es <= 10.
La condición es siempre verdadera; x = -5 o x = 999 entran igual.
❌ Contraejemplo 2 — comparación triple¶
if (a < b < c)
{
ordenar(a, b, c);
}Por qué falla: se evalúa (a < b) < c. El resultado no dice si b < c; es un
número 0 o 1 comparado contra c, con significado accidental.
✅ Ejemplo conforme 1 — rango con &&¶
if (0 <= x && x <= 10)
{
aceptar(x);
}Cada comparación se evalúa sobre x y el && combina ambas; el rango se
verifica de verdad.
✅ Ejemplo conforme 2 — cadena de relaciones¶
if (a < b && b < c)
{
ordenar(a, b, c);
}La relación transitiva queda explícita y el cortocircuito evita evaluar de más cuando la primera comparación falla.
⚠️ Casos límite¶
Límites de
int:0 <= x && x <= INT_MAXes válido; cuidar el overflow en cálculos intermedios, no en la comparación.Punto flotante:
0.0 <= f && f <= 1.0sigue expuesto al redondeo; comparar con tolerancia (ver la ficha de antipatrón 0x301Fh).Precedencia de
&&vs||: si además se mezcla||, agregar paréntesis (ver 0x1013h: Detector de expresiones booleanas complejas sin paréntesis aclaratorios).
Cómo detectarla¶
| Herramienta | Comando | Señal |
|---|---|---|
gaff | gaff check archivo.c | Regla 0x1010h: comparación encadenada (autofix). |
clang | clang -Wall -Wextra | warning: comparison of constant with boolean expression. |
| Revisión manual | — | a < b < c en cualquier condición. |
Checklist de autocontrol¶
¿Alguna condición encadena más de un operador relacional?
¿Separé cada comparación con
&&?¿El rango escrito verifica realmente cada extremo?
¿Agregué paréntesis si además hay
||?
Reglas relacionadas¶
0x1013h: Detector de expresiones booleanas complejas sin paréntesis aclaratorios — paréntesis obligatorios al mezclar
&&y||.0x1004h: Las condiciones complejas deben simplificarse o comentarse — extraer subcondiciones con nombre para mayor claridad.
0x1005h: Reemplazá las condiciones ambiguas basadas en la ‘veracidad’ (truthiness) del tipo de dato — comparaciones explícitas según el tipo del dato.