Regla 0x1005h: Reemplazá las condiciones ambiguas basadas en la 'veracidad' (truthiness) del tipo de dato
Estructuras de control y flujo (0x10XX)
0x1005h: Reemplazá las condiciones ambiguas basadas en la ‘veracidad’ (truthiness) del tipo de dato¶
Enunciado normativo¶
DEBEN escribirse comparaciones explícitas que reflejen el tipo del dato: un
charse compara contra'\0', un puntero contraNULL, unboolcontratrueofalse, y un entero contra0. NO DEBE depender de la veracidad implícita de un valor numérico o de un puntero.
¿Por qué existe esta regla?¶
El problema¶
En C, cualquier escalar distinto de cero es verdadero: if (x) funciona igual
para un int, un char y un puntero. Esa comodidad borra la distinción entre
tres chequeos que significan cosas distintas. Cuando el lector ve if (ptr)
debe adivinar si el autor quiso preguntar por “puntero no nulo” o por “contenido
distinto de cero”.
La comparación explícita elimina la adivinanza. En el caso del char evita
confundir el carácter '0' (cuyo valor es 48) con el carácter nulo '\0'
(valor 0), y en el caso del strcmp evita invertir la condición.
Consecuencias de violarla¶
| Tipo de consecuencia | Efecto concreto |
|---|---|
| Bug lógico | if (strcmp(a, b)) ejecuta la rama cuando las cadenas son distintas. |
| Legibilidad | El lector debe inferir la intención del tipo del dato. |
Fundamento en el estándar y en la cátedra¶
ISO/IEC 9899:2011 §6.8.4.1 establece que la condición de un if compara contra
cero; §6.3.1.2 fija las conversiones aritméticas usuales. La cátedra obliga a
hacer explícita esa comparación para que el código no dependa de reglas
implícitas. Es complementaria de 0x3008h: Los punteros nulos deben ser inicializados y comparados con NULL, no con 0 para punteros contra NULL y
de 0x301Ah: Validador de uso idiomático de tipos booleanos estándar para el tipo bool estándar.
Alcance y excepciones¶
Aplica a toda condición y a todo operador que consuma un booleano.
Tensión documentada: 0x1005h: Reemplazá las condiciones ambiguas basadas en la ‘veracidad’ (truthiness) del tipo de dato considera redundante comparar un
boolcontratrue; la cátedra prioriza la explicitidad y admite ambas formas, pero exige coherencia dentro del mismo archivo.Una función que devuelve
boolya expresa su intención; elif (es_valido)es aceptable. La prohibición apunta a tipos no booleanos.
Ejemplos exhaustivos¶
❌ Contraejemplo 1 — int y char evaluados por veracidad¶
if (cantidad)
{
procesar(cantidad);
}
if (caracter)
{
analizar(caracter);
}Por qué falla: cantidad debería compararse contra 0 y caracter contra
'\0'. Si se pretendía detectar un carácter válido, el '0' (48) también pasa
la condición, y el carácter nulo también, según lo que se quería.
❌ Contraejemplo 2 — resultado de strcmp usado como booleano¶
if (strcmp(nombre, "admin"))
{
dar_acceso();
}Por qué falla: strcmp devuelve 0 cuando las cadenas son iguales;
entonces la rama se ejecuta cuando son diferentes, justo lo contrario de la
intención.
✅ Ejemplo conforme 1 — comparaciones explícitas por tipo¶
if (cantidad != 0)
{
procesar(cantidad);
}
if (caracter != '\0')
{
analizar(caracter);
}Cada comparación declara qué se mide y contra qué valor neutro; el lector no infiere nada.
✅ Ejemplo conforme 2 — strcmp explícito y bool coherente¶
if (strcmp(nombre, "admin") == 0)
{
dar_acceso();
}
bool es_valido = puntaje >= APROBADO;
if (es_valido)
{
promover();
}El resultado de strcmp se compara contra 0 y la variable bool se usa
directamente; la intención queda expuesta sin ambigüedad.
⚠️ Casos límite¶
'0'vs'\0': son valores distintos (48 y 0); la comparación explícita evita tratarlos como el mismo “falso”.Mezcla de signos:
int i = -1; size_t n = 10; if (i < n)convierteia sin signo y da un valor enorme (ver 0x1005h: Reemplazá las condiciones ambiguas basadas en la ‘veracidad’ (truthiness) del tipo de dato).
Cómo detectarla¶
| Herramienta | Comando | Señal |
|---|---|---|
gaff | gaff check archivo.c | Regla 0x1005h: condición implícita. |
gcc | gcc -Wall -Wextra -Wsign-compare | warning: comparison of integer expressions of different signedness. |
| Revisión manual | — | if (var) donde var no es bool. |
Checklist de autocontrol¶
¿Cada
charse compara contra'\0'?¿Cada entero se compara contra
0?¿Los resultados de
strcmpse comparan contra0?¿Las variables
boolse usan de forma coherente en todo el archivo?
Reglas relacionadas¶
0x3008h: Los punteros nulos deben ser inicializados y comparados con NULL, no con 0 — refuerza: punteros contra
NULL, no contra0.0x301Ah: Validador de uso idiomático de tipos booleanos estándar — complementa: uso del tipo
bool,trueyfalseestándar.0x1005h: Reemplazá las condiciones ambiguas basadas en la ‘veracidad’ (truthiness) del tipo de dato — antipatrón específico de
strcmpusado como booleano.
Antipatrón: Comparación booleana explícita redundante¶
Síntoma en el código del estudiante¶
Aparecen comparaciones contra true, false, 1 o 0 sobre variables que ya
son booleanas, agregando ruido a la condición:
if (es_valido == true)
{
avanzar();
}Diagnóstico¶
Mecanismo del defecto¶
En C cualquier valor distinto de cero es verdadero y el cero es falso
(ISO/IEC 9899:2011 §6.8.4.1). Comparar un bool contra true produce
true == true o false == true, es decir, el mismo valor que la variable
original. La comparación es una tautología que no agrega información.
Consecuencia observable¶
No hay error de ejecución; el código funciona igual. El costo es de lectura: el
lector procesa dos comparaciones donde bastaba una y debe confirmar que
es_valido == true no esconde una negación. Además, el patrón invita a
confundir = con == en un contexto donde el error queda tapado.
Fundamento en el estándar C11¶
ISO/IEC 9899:2011 §6.8.4.1 establece que la condición de un if compara contra
cero, y §7.18 (<stdbool.h>) define true como 1 y false como 0. La
comparación bool == true es, por lo tanto, siempre equivalente al valor de la
variable. La cátedra prioriza la claridad y prefiere la forma directa.
Corrección idiomática¶
❌ Código con el antipatrón¶
if (es_valido == true)
{
avanzar();
}
if (encontrado == false)
{
seguir_buscando();
}✅ Código refactorizado¶
if (es_valido)
{
avanzar();
}
if (!encontrado)
{
seguir_buscando();
}La forma directa y la negación con ! expresan la misma condición sin la
comparación redundante. Nota: esta ficha entra en tensión con
0x1005h: Reemplazá las condiciones ambiguas basadas en la ‘veracidad’ (truthiness) del tipo de dato; la cátedra admite ambas formas, pero exige coherencia dentro del
mismo archivo.
Errores típicos al compilar o ejecutar¶
No compila con error. Con -Wall puede aparecer:
warning: comparison is always false due to limited range of data type
solo si se compara contra un valor imposible, no por la redundancia.
El bug real aparece cuando el autor escribe:
if (es_valido = false) // asigna en lugar de compararChecklist de verificación¶
¿Comparo una variable
boolcontratrueofalse?¿Puedo reemplazar la comparación por la variable o por
!variable?¿El archivo usa un solo estilo de forma coherente?
¿Alguna comparación booleana esconde un
=en lugar de==?
Reglas relacionadas¶
0x1005h: Reemplazá las condiciones ambiguas basadas en la ‘veracidad’ (truthiness) del tipo de dato — norma este antipatrón: comparaciones explícitas según el tipo.
0x301Ah: Validador de uso idiomático de tipos booleanos estándar — uso idiomático del tipo
boolestándar.0x1009h: Prohibición de asignaciones simples dentro de condiciones lógicas — el
=accidental en condiciones es un riesgo cercano.
Antipatrón: Comparación lógica invertida con strcmp() en condicional¶
Síntoma en el código del estudiante¶
Se usa el resultado de strcmp directamente como booleano, sin compararlo
contra 0:
if (strcmp(nombre, "admin"))
{
dar_acceso();
}Diagnóstico¶
Mecanismo del defecto¶
strcmp devuelve un entero negativo, 0 o positivo según el orden
lexicográfico (ISO/IEC 9899:2011 §7.24.4.2). Devuelve 0 cuando las cadenas son
iguales. Al usarlo directamente como condición, el cero se interpreta como
falso y cualquier otro valor como verdadero: la rama se ejecuta cuando las
cadenas son diferentes, justo al revés de lo que sugiere el nombre.
Consecuencia observable¶
La validación de credenciales, nombres o claves queda invertida: se concede acceso a cualquier texto que no coincida con el esperado y se lo niega al correcto. Es un bug grave de seguridad que compila sin advertencias y se manifiesta como lógica incomprensible.
Fundamento en el estándar C11¶
ISO/IEC 9899:2011 §7.24.4.2 especifica el valor de retorno de strcmp. Debido
a que 0 significa igualdad, la comparación explícita es obligatoria. La
cátedra exige comparar contra 0 (regla 0x1005h) y distingue el chequeo de
cadenas del de punteros y caracteres.
Corrección idiomática¶
❌ Código con el antipatrón¶
if (strcmp(nombre, "admin"))
{
dar_acceso();
}✅ Código refactorizado¶
if (strcmp(nombre, "admin") == 0)
{
dar_acceso();
}
if (strcmp(nombre, "admin") != 0)
{
denegar_acceso();
}La comparación contra 0 hace explícito que 0 es igualdad y != 0 es
desigualdad. El lector ya no tiene que recordar la convención de strcmp.
Errores típicos al compilar o ejecutar¶
No hay error de compilación ni advertencia por defecto.
En ejecución, la rama se ejecuta para cualquier nombre distinto de "admin":
dar_acceso() se llama con nombres incorrectos. Un atacante entra con
cualquier usuario mientras no se llame "admin".Checklist de verificación¶
¿Uso
strcmpcomo condición directa?¿La comparación contra
0está explícita?¿Distinguí
== 0(igualdad) de!= 0(desigualdad)?¿Probé el caso de cadenas iguales y el de cadenas distintas?
Reglas relacionadas¶
0x1005h: Reemplazá las condiciones ambiguas basadas en la ‘veracidad’ (truthiness) del tipo de dato — norma este antipatrón: comparaciones explícitas por tipo.
0x5006h: Preferí fgets sobre gets y scanf para leer cadenas — preferir
fgetspara leer cadenas de entrada.0x5004h: Todas las operaciones con cadenas deben ser seguras — operaciones seguras con cadenas.
Antipatrón: Comparación entre tipos enteros con y sin signo en condición¶
Síntoma en el código del estudiante¶
Se compara un entero con signo contra uno sin signo (por ejemplo int contra
size_t) sin controlar la conversión:
int i = -1;
size_t n = 10;
if (i < n)
{
procesar(i);
}Diagnóstico¶
Mecanismo del defecto¶
Cuando un operando con signo se compara contra uno sin signo de rango igual o
mayor, el valor con signo se convierte implícitamente a sin signo
(ISO/IEC 9899:2011 §6.3.1.8). -1 se convierte en el mayor valor del tipo
size_t (SIZE_MAX), que es enorme. La comparación i < n resulta entonces
falsa, al revés de lo esperado.
Consecuencia observable¶
El if no entra aunque i sea negativo y menor que n; o bien un lazo que
recorre hacia atrás se desborda. También aparece al recorrer un arreglo con un
índice int que se vuelve negativo: se convierte a un índice gigantesco y
provoca un acceso fuera de rango.
Fundamento en el estándar C11¶
ISO/IEC 9899:2011 §6.3.1.8 define las conversiones aritméticas usuales: si el
tipo sin signo tiene rango mayor o igual, el operando con signo se convierte a
sin signo. La cátedra exige tipos consistentes y size_t para índices
(regla 0x3010h), evitando la conversión accidental (regla 0x1005h).
Corrección idiomática¶
❌ Código con el antipatrón¶
int i = -1;
size_t n = 10;
if (i < n)
{
procesar(i);
}✅ Código refactorizado¶
size_t i = 0;
size_t n = 10;
if (i < n)
{
procesar(i);
}Ambos operandos son del mismo tipo sin signo y la comparación es segura. Si el
valor con signo debe conservarse, se valida primero: if (i >= 0 && (size_t)i < n).
Errores típicos al compilar o ejecutar¶
Con -Wsign-compare (incluida en -Wextra):
warning: comparison of integer expressions of different signedness:
'int' and 'size_t' {aka 'long unsigned int'} [-Wsign-compare]
En ejecución, i = -1 se convierte a 18446744073709551615 y la condición
es falsa. Con un índice negativo, el acceso desborda el arreglo.Checklist de verificación¶
¿Comparo tipos con signo y sin signo?
¿El operando con signo puede ser negativo?
¿Unifiqué los tipos o convertí de forma controlada?
¿Usé
size_tpara índices y tamaños?
Reglas relacionadas¶
0x1005h: Reemplazá las condiciones ambiguas basadas en la ‘veracidad’ (truthiness) del tipo de dato — norma este antipatrón: comparaciones explícitas y coherentes.
0x3010h: Las variables que representan tamaños o índices de arreglos deben ser de tipo size_t — índices y tamaños de arreglos con
size_t.0x300Ch: Verificá siempre los límites de los arreglos antes de acceder a sus elementos — verificar límites antes de acceder a un arreglo.