Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Regla 0x5009h: Prohibición de división entera no intencional asignada a flotantes

Compilacion, preprocesador y seguridad (0x50XX)

Universidad Nacional de Río Negro

0x5009h: Prohibición de división entera no intencional asignada a flotantes

Enunciado normativo

NO DEBE asignarse a una variable flotante el resultado de una división cuyos dos operandos son enteros, salvo que la truncación sea intencional. DEBE promoverse explícitamente un operando con literal flotante o cast.

¿Por qué existe esta regla?

El problema

El operador / decide su semántica según los tipos de los operandos. Si ambos son enteros, hace división entera y descarta la parte fraccionaria antes de que ocurra cualquier conversión a double. La asignación al flotante es posterior e inútil: el daño ya está hecho. Para que / sea real, al menos un operando debe ser de punto flotante en el momento de evaluar la expresión.

Es un error silencioso: no hay advertencia del compilador, el programa compila y devuelve 0.0 en vez de 0.5. El estudiante lo descubre recién al imprimir el resultado, y suele culpar al formato de salida.

Consecuencias de violarla

Tipo de consecuenciaEfecto concreto
Resultado incorrectodouble t = 1 / 2; guarda 0.0, no 0.5.
Bug silenciosoEl compilador no advierte; el error viaja hasta la salida.
LógicaPromedios, tasas y porcentajes quedan truncados a cero.
División por ceroresto / n con n entero puede abortar donde se esperaba un valor real.

Fundamento en el estándar y en la cátedra

ISO/IEC 9899:2011 §6.5.5 define / para operandos aritméticos y §6.3.1.8 las conversiones aritméticas usuales: si ambos operandos son enteros, la división es entera y el resultado tiene tipo entero. La cátedra prohíbe el patrón porque es una de las causas más frecuentes de resultados «casi correctos» en los prácticos.

Alcance y excepciones

Aplica cuando ambos operandos de / son enteros y el resultado se asigna o pasa a un contexto flotante. Excepciones: la división entera es correcta si el resultado se usa como entero (por ejemplo, mitad = total / 2 para índices), o si se explicita la intención con un cast antes de dividir. Un cast defensivo aquí no es redundante y no cae bajo 0x301Bh: Prohibición de casts de tipo innecesarios o redundantes.

Ejemplos exhaustivos

❌ Contraejemplo 1 — Literales enteros

double tasa = 1 / 2;
printf("%f\n", tasa);

Por qué falla: ambos operandos son int, así que 1 / 2 vale 0; luego se convierte a 0.0. Para obtener 0.5 hay que escribir 1.0 / 2.0.

❌ Contraejemplo 2 — Promedio con suma entera

double promedio(const int datos[], size_t n)
{
    int suma = 0;
    for (size_t i = 0; i < n; i++) {
        suma += datos[i];
    }
    return suma / n;
}

Por qué falla: suma y n son enteros, de modo que el promedio trunca. Si suma vale 7 y n vale 2, el retorno es 3.0 en lugar de 3.5.

✅ Ejemplo conforme 1 — Literal flotante y cast

double tasa = 1.0 / 2.0;

double promedio(const int datos[], size_t n)
{
    int suma = 0;
    for (size_t i = 0; i < n; i++) {
        suma += datos[i];
    }
    return (double)suma / (double)n;
}

El literal 1.0 y los cast promueven la operación a double antes de dividir, de modo que la parte fraccionaria sobrevive.

✅ Ejemplo conforme 2 — División entera deliberada

int mitad_entera(int total)
{
    return total / 2;
}

double mitad_real(int total)
{
    return (double)total / 2.0;
}

mitad_entera usa / para calcular un índice: la truncación es la intención y el resultado es entero. mitad_real documenta su intención con el cast. Al llamador le queda claro cuál es cuál.

⚠️ Casos límite

Cómo detectarla

HerramientaComandoSeñal
gaffgaff check archivo.cReporta 0x5009h al detectar / entre enteros en contexto flotante.
gcc / clanggcc -std=c11 -Wall -Wextra -Werror -pedantic -Wconversion archivo.cCon -Wconversion aparece conversion from 'int' to 'double' may change value.
cppcheckcppcheck --enable=warning archivo.cDivision by zero o advertencias de promoción.

Checklist de autocontrol

Reglas relacionadas

Antipatrón: División entera silenciosa asignada a flotante

Síntoma en el código del estudiante

Se calcula un cociente con dos operandos int y el resultado se guarda en un float o double, o se imprime con %f:

float tasa = 1 / 2;
double promedio = suma / cantidad;
double porcentaje = aciertos / total * 100;

El código parece correcto porque el destino es flotante. El error está en los operandos, que son enteros.

Diagnóstico

Mecanismo del defecto

En C, el tipo del resultado de a / b se decide antes de la asignación, según las conversiones aritméticas usuales (C11 §6.3.1.8): si ambos operandos son enteros, la operación es división entera y descarta la parte fraccionaria truncando hacia cero (C11 §6.5.5p5). Recién después el resultado entero se convierte al tipo flotante del destino. Por eso 1 / 2 produce 0 (no 0.5) y recién entonces se promueve a 0.0f: la información ya se perdió cuando se convierte.

Es un error de tipo semántico: no hay advertencia obligatoria, el compilador ve una conversión int -> float perfectamente legal.

Consecuencia observable

Fundamento en el estándar C11

El estándar define la división entera como truncamiento hacia cero (C11 §6.5.5p5). Para obtener división real, al menos un operando debe ser de tipo flotante antes de la operación, de modo que la promoción ocurra primero y el cociente conserve los decimales. La cátedra prohíbe confiar en la conversión implícita porque oculta la intención y produce resultados difíciles de rastrear.

La división entera por cero, además, es comportamiento indefinido (C11 §6.5.5p5): no es una excepción controlada y en general termina en SIGFPE.

Corrección idiomática

❌ Código con el antipatrón
#include <stdio.h>

double calcular_promedio(int suma, int cantidad)
{
    double promedio = suma / cantidad;
    return promedio * 100.0;
}
✅ Código refactorizado
#include <stdio.h>

double calcular_promedio(int suma, int cantidad)
{
    if (cantidad == 0) {
        return 0.0;
    }

    double promedio = (double)suma / (double)cantidad;
    return promedio * 100.0;
}

Alternativas equivalentes y claras: usar un literal flotante (suma / 100.0) o declarar la variable acumuladora como double desde el comienzo. El cast explícito documenta la intención y evita la división entera.

Errores típicos al compilar o ejecutar

Con advertencias de conversión, un caso cercano sí se detecta:

aviso.c:4:29: warning: conversion from 'int' to 'float' may change value [-Wconversion]

Con una división por cero literal:

aviso.c:4:29: warning: division by zero [-Wdiv-by-zero]

En ejecución, la división entera por cero no controlada aborta con Floating point exception (core dumped).

Checklist de verificación

Reglas relacionadas