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 0x4008h: Validación obligatoria del valor de retorno de fclose() en modo escritura

Archivos y E/S (0x40XX)

Universidad Nacional de Río Negro

0x4008h: Validación obligatoria del valor de retorno de fclose() en modo escritura

Enunciado normativo

DEBE verificarse que fclose retorne distinto de EOF al cerrar un flujo abierto para escritura ("w", "a", "wb", "ab" o sus variantes de actualización). Un retorno EOF DEBE reportarse como error.

El cierre de un flujo de salida no es una formalidad: es la última operación que puede fallar y la única que garantiza que los datos llegaron al disco.

¿Por qué existe esta regla?

El problema

stdio trabaja con búferes. Al llamar a fprintf o fwrite, los datos suelen quedar en memoria y no se escriben de inmediato en el dispositivo. Recién cuando el búfer se llena, cuando se llama a fflush o cuando se cierra el flujo con fclose, el sistema intenta la escritura física.

Eso significa que una escritura puede tener éxito a nivel de biblioteca y fallar después, en el vaciado final. El caso típico es el disco lleno (ENOSPC) o un error de E/S (EIO) que se manifiesta recién en fclose. Si el programa ignora el retorno, cree que guardó todo cuando en realidad perdió datos. El error es silencioso: no hay excepción, no hay mensaje, solo un archivo truncado.

La única forma de detectar esa clase de fallo es mirar el valor de retorno de fclose, reportarlo y decidir si hay que reintentar o abortar.

Consecuencias de violarla

Tipo de consecuenciaEfecto concreto
Pérdida de datosEl archivo queda incompleto y el programa lo reporta como éxito.
Bug silenciosoUn disco lleno no genera ningún aviso; el usuario confía en datos que no existen.
Estado inconsistenteUn archivo parcialmente escrito puede corromper ejecuciones posteriores.

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

ISO/IEC 9899:2011 §7.21.5.1 define fclose: retorna cero si tiene éxito y EOF si detecta un error, y descarga cualquier dato aún no escrito. La cátedra adopta la regla porque el trabajo con archivos de salida es parte central de la materia y la pérdida silenciosa de datos es el peor defecto posible en una entrega.

Alcance y excepciones

Aplica a todo fclose de un flujo abierto para escritura o actualización. Para flujos de solo lectura la verificación es menos crítica, pero sigue siendo buena práctica por uniformidad.

Excepción razonable: cerrar stdin/stdout/stderr al final del proceso puede omitir la verificación si el programa no depende de esa salida para su corrección.

Ejemplos exhaustivos

❌ Contraejemplo 1 — Retorno de fclose descartado

FILE *f = fopen("log.txt", "w");
if (f == NULL) {
    return -1;
}
fprintf(f, "resultado: %d\n", total);
fclose(f);
return 0;

Por qué falla: si el disco se llenó, fprintf pudo haber dejado los datos en el búfer y fclose falla al vaciarlo. El programa retorna éxito y el archivo de log queda vacío o truncado sin que nadie lo advierta.

❌ Contraejemplo 2 — Retorno anticipado que saltea el cierre verificado

int guardar(const char *ruta, int valor)
{
    FILE *f = fopen(ruta, "w");
    if (f == NULL) {
        return -1;
    }
    if (valor < 0) {
        return -2;   /* f no se cierra ni se verifica */
    }
    if (fprintf(f, "%d\n", valor) < 0) {
        return -3;   /* tampoco cierra */
    }
    return fclose(f) == EOF ? -4 : 0;
}

Por qué falla: dos ramas retornan sin cerrar el flujo, con lo que además de no verificar el vaciado se fuga el descriptor (ver 0x4004h: Mantené la simetría de recursos al abrir y cerrar archivos en el mismo nivel de abstracción).

✅ Ejemplo conforme 1 — Verificar el cierre y reportar la causa

#include <stdio.h>

FILE *f = fopen("log.txt", "w");
if (f == NULL) {
    perror("log.txt");
    return -1;
}
if (fprintf(f, "resultado: %d\n", total) < 0) {
    perror("fprintf");
}
if (fclose(f) == EOF) {
    perror("fclose");
    return -1;
}
return 0;

El retorno de fclose se compara con EOF y, ante fallo, se reporta con perror conservando la causa del sistema (0x4003h: Utilizá errno, perror y strerror para reportar fallos del sistema operativo de manera precisa).

✅ Ejemplo conforme 2 — fflush explícito antes de cerrar

if (fwrite(datos, 1, n, f) != n) {
    perror("fwrite");
}
if (fflush(f) == EOF) {
    perror("fflush");
}
if (fclose(f) == EOF) {
    perror("fclose");
}

Forzar el vaciado con fflush separa el error de escritura del de cierre y hace que el diagnóstico apunte a la operación concreta que falló.

⚠️ Casos límite

Cómo detectarla

HerramientaComandoSeñal
gaffgaff check archivo.cRegla 0x4008h: fclose sin comparación contra EOF.
gccgcc -Wall -Wextra -std=c11 archivo.c-Wunused-result si se ignora el retorno.
Revisión manualTodo fclose de un flujo "w"/"a" debe consumir su resultado.

Checklist de autocontrol

Reglas relacionadas