Regla 0x1009h: Prohibición de asignaciones simples dentro de condiciones lógicas
Estructuras de control y flujo (0x10XX)
0x1009h: Prohibición de asignaciones simples dentro de condiciones lógicas¶
Enunciado normativo¶
NO DEBE usarse el operador de asignación
=dentro de la condición de unif,while,foro de cualquier otra estructura de control. La asignación DEBE realizarse en una sentencia previa y la condición DEBE limitarse a comparar.
¿Por qué existe esta regla?¶
El problema¶
= y == se parecen lo suficiente como para que un dedo cambie uno por otro.
El compilador no siempre avisa: if (x = 5) es válido y asigna 5, condición
siempre verdadera. El programa compila, arranca y produce un resultado
incorrecto que parece inexplicable.
Aun cuando la asignación sea intencional, mezclar “guardar” y “preguntar” en la misma sentencia viola el principio de una acción por sentencia. El lector no puede saber de un vistazo si hubo intención o error.
Consecuencias de violarla¶
| Tipo de consecuencia | Efecto concreto |
|---|---|
| Bug silencioso | if (estado = ACTIVO) deja estado en ACTIVO y siempre entra. |
| Pérdida de datos | La variable se sobrescribe con el valor de la comparación. |
| Legibilidad | No se distingue la intención de asignar de la de comparar. |
| Depuración | El cambio de estado ocurre en una línea que no parece asignar. |
Fundamento en el estándar y en la cátedra¶
ISO/IEC 9899:2011 §6.5.16 define la asignación como expresión que devuelve el
valor asignado; por eso es sintácticamente legal dentro de una condición. La
cátedra la prohíbe por su historial como causa de bugs. 0x1012h: Prohibición de expresiones de asignación dentro de estructuras de control extiende
la prohibición a las asignaciones embebidas con comparación, como
while ((c = getchar()) != EOF).
Alcance y excepciones¶
Prohibido en toda condición de control:
if,while,for,do-while.No hay excepción ni aun con paréntesis dobles; si hace falta asignar, se escribe antes.
Una expresión de inicialización en el
for(int i = 0) no es una condición y no está alcanzada.
Ejemplos exhaustivos¶
❌ Contraejemplo 1 — = accidental por ==¶
if (estado = ACTIVO)
{
reactivar();
}Por qué falla: asigna ACTIVO a estado y entra siempre que ACTIVO sea
distinto de cero. El estado real del sistema se pierde en la comparación.
❌ Contraejemplo 2 — asignación oculta en un while¶
int total = 0;
while (valor = siguiente())
{
total += valor;
}Por qué falla: valor se pisa en cada iteración y la condición es verdadera
mientras el valor leído no sea cero. Si la intención era comparar, el lazo no
termina cuando debería.
✅ Ejemplo conforme 1 — asignación separada de la comparación¶
estado = obtener_estado();
if (estado == ACTIVO)
{
reactivar();
}La asignación es una acción visible y la condición solo pregunta. El error de tipeo queda imposible.
✅ Ejemplo conforme 2 — lectura separada en el lazo¶
int valor = siguiente();
int total = 0;
while (valor != 0)
{
total += valor;
valor = siguiente();
}El avance es explícito y la condición compara contra 0; se lee sin ambigüedad
qué detiene el lazo.
⚠️ Casos límite¶
Constantes con valor 0:
if (x = 0)no entra nunca; el bug es el opuesto y todavía más difícil de notar.==mal escrito: el mismo problema aparece al invertir los operadores; no confiar en la suerte.Código legado:
while ((c = getchar()) != EOF)es correcto pero prohibido por 0x1012h: Prohibición de expresiones de asignación dentro de estructuras de control; reescribir con lectura previa.
Cómo detectarla¶
| Herramienta | Comando | Señal |
|---|---|---|
gaff | gaff check archivo.c | Regla 0x1009h: asignación en condición. |
gcc | gcc -Wall -Wextra -Wparentheses | warning: suggest parentheses around assignment used as truth value. |
| Búsqueda | grep -nE "if \([^=]*[^=!<>]=[^=]" archivo.c | Posibles asignaciones en condiciones. |
Checklist de autocontrol¶
¿Alguna condición usa
=en lugar de==?¿Hay asignaciones dentro de
whileofor?¿Separé la lectura o el cómputo de la comparación?
¿Compilé con
-Wparenthesespara descartar el warning?
Reglas relacionadas¶
0x1012h: Prohibición de expresiones de asignación dentro de estructuras de control — prohibición de asignaciones embebidas con comparación.
0x3003h: No mezcles operaciones de asignación y comparación en una sola línea — no mezclar asignación y comparación en una línea.
0x100Ah: Prohibición de estructuras de control con cuerpo vacío (if (...);) — el
;vacío es otra trampa sintáctica silenciosa.
Antipatrón: Asignación accidental en condición lógica (if (x = 5))¶
Síntoma en el código del estudiante¶
La condición de un if o while usa = en lugar de ==, y la variable
aparenta compararse pero en realidad se sobrescribe:
if (x = 5)
{
procesar();
}Diagnóstico¶
Mecanismo del defecto¶
En C la asignación es una expresión que devuelve el valor asignado
(ISO/IEC 9899:2011 §6.5.16). El if evalúa ese valor: x = 5 asigna 5 y la
condición resulta verdadera. La variable queda modificada de forma lateral, sin
que ninguna línea lo anuncie.
Consecuencia observable¶
El if siempre entra (si el valor asignado no es cero) y x cambia de valor.
En un while, el lazo puede no terminar nunca o terminar antes de tiempo. El
compilador no distingue la intención: compila sin error y, a lo sumo, avisa de
la asignación usada como valor de verdad si se activa -Wparentheses.
Fundamento en el estándar C11¶
ISO/IEC 9899:2011 §6.5.16 define la asignación como expresión con valor, y
§6.8.4.1 permite cualquier expresión escalar como condición. El estándar no
prohíbe el patrón; la cátedra sí, porque su historial como causa de bugs es
extenso. La prohibición es de la regla 0x1009h.
Corrección idiomática¶
❌ Código con el antipatrón¶
if (x = 5)
{
procesar();
}
while (valor = siguiente())
{
acumular(valor);
}✅ Código refactorizado¶
if (x == 5)
{
procesar();
}
valor = siguiente();
while (valor != 0)
{
acumular(valor);
valor = siguiente();
}La comparación usa == y la asignación se separa de la condición. El while
expone su corte comparando contra 0 y el avance es explícito.
Errores típicos al compilar o ejecutar¶
Con -Wparentheses (incluida en -Wall):
warning: suggest parentheses around assignment used as truth value
[-Wparentheses]
Sin advertencias: el programa compila y entra siempre a la rama,
o el while nunca termina si el valor asignado nunca llega a cero.Checklist de verificación¶
¿Cada comparación usa
==o!=en lugar de=?¿Hay asignaciones dentro de
ifowhile?¿Separé la lectura o el cómputo de la comparación?
¿Compilé con
-Wparenthesesy revisé los avisos?
Reglas relacionadas¶
0x1009h: Prohibición de asignaciones simples dentro de condiciones lógicas — norma este antipatrón.
0x1012h: Prohibición de expresiones de asignación dentro de estructuras de control — prohíbe también la asignación comparada embebida.
0x3003h: No mezcles operaciones de asignación y comparación en una sola línea — no mezclar asignación y comparación en una línea.