Regla 0x4003h: Utilizá errno, perror y strerror para reportar fallos del sistema operativo de manera precisa
Archivos y E/S (0x40XX)
0x4003h: Utilizá errno, perror y strerror para reportar fallos del sistema operativo de manera precisa¶
Enunciado normativo¶
DEBE reportarse todo fallo de E/S con un mensaje que incluya la causa informada por el sistema, usando
errno,perrorostrerroren lugar de un texto genérico.
Un mensaje que solo dice “Error” obliga a adivinar; el mensaje del sistema distingue “no existe” de “permiso denegado” de “demasiados archivos abiertos”.
¿Por qué existe esta regla?¶
El problema¶
La biblioteca C comunica la causa de los fallos del sistema operativo por una
variable global, errno, declarada en <errno.h>. Cuando una llamada como
fopen, fread o fwrite falla, el sistema operativo deposita allí un código
entero (ENOENT, EACCES, EMFILE, etc.). Ese código no sirve de nada si el
programa lo ignora y se limita a imprimir “no se pudo abrir”.
errno tiene dos propiedades que hay que respetar. Primero, solo es válido
inmediatamente después de una llamada que falló: las funciones exitosas no lo
limpian, así que mirarlo sin que hubo fallo puede reportar un error viejo.
Segundo, cualquier otra llamada que falle puede sobreescribirlo: si entre el
fallo y el reporte se invoca otra función, hay que guardar el valor antes.
Consecuencias de violarla¶
| Tipo de consecuencia | Efecto concreto |
|---|---|
| Diagnóstico inútil | El usuario no puede distinguir un archivo ausente de uno sin permisos. |
| Depuración lenta | El equipo pierde tiempo reproduciendo fallos que el sistema ya describió. |
| Bug silencioso | Un errno consultado tarde reporta la causa de otra operación distinta. |
| Mala experiencia | Un programa robusto parece roto cuando en realidad solo faltaba un permiso. |
Fundamento en el estándar y en la cátedra¶
ISO/IEC 9899:2011 §7.5 declara errno como objeto modificable con alcance de
hilo. §7.21.10.4 define perror, que imprime a stderr el mensaje asociado al
errno actual precedido por el texto del llamador. §7.24.6.2 define strerror,
que traduce un código a una cadena legible. La cátedra exige usarlos porque el
diagnóstico preciso es parte de la robustez, no un adorno.
Alcance y excepciones¶
Aplica a todo reporte de fallo de E/S y de llamadas de biblioteca que informen
por errno. No exige formato fijo: perror alcanza para mensajes simples y
strerror permite componer mensajes con datos adicionales. Conviene enviar el
diagnóstico a stderr, no a stdout, para no mezclarlo con la salida normal.
Ejemplos exhaustivos¶
❌ Contraejemplo 1 — Mensaje genérico sin causa del sistema¶
FILE *f = fopen("config.txt", "r");
if (f == NULL) {
printf("No se pudo abrir el archivo\n");
}Por qué falla: el programador y el usuario quedan sin saber si el archivo no
existe, si falta permiso o si se agotaron los descriptores. La información ya
estaba disponible en errno y se descartó.
❌ Contraejemplo 2 — Consultar errno después de otra llamada¶
FILE *f = fopen(ruta, "r");
if (f == NULL) {
fclose(otro_flujo);
fprintf(stderr, "%s\n", strerror(errno));
}Por qué falla: fclose puede fallar y sobreescribir errno, de modo que el
mensaje describe la segunda operación y no la apertura. Hay que copiar errno
a una variable local antes de cualquier otra llamada.
✅ Ejemplo conforme 1 — perror inmediatamente después del fallo¶
#include <stdio.h>
FILE *f = fopen(ruta, "r");
if (f == NULL) {
perror(ruta);
return -1;
}perror lee el errno vigente y escribe a stderr un mensaje del estilo
archivo.txt: No such file or directory, con la causa exacta y sin código
extra.
✅ Ejemplo conforme 2 — Guardar errno y componer con strerror¶
#include <errno.h>
#include <stdio.h>
#include <string.h>
FILE *f = fopen(ruta, "r");
if (f == NULL) {
int motivo = errno;
fprintf(stderr, "no se pudo abrir '%s': %s\n", ruta, strerror(motivo));
return -1;
}Copiar errno a motivo antes de otras llamadas preserva la causa, y
strerror permite enriquecer el mensaje con la ruta y el contexto. Incluye
las cabeceras correctas (ver 0x500Bh: Inclusión obligatoria de cabeceras estándar para funciones de la biblioteca C).
⚠️ Casos límite¶
errnono se limpia en éxito: solo debe consultarse cuando la función indicó fallo por su retorno (NULL,EOFo negativo).Varias operaciones: guardá
errnoen una variable por cada fallo que quieras reportar más tarde.Códigos desconocidos:
strerrorpuede no tener un texto útil para códigos no estándar; igualmente es mejor que un mensaje vacío.perrorusa elerrnoactual: llamarlo después de otra operación exitosa no borra el error, pero después de otra fallida lo enmascara.
Cómo detectarla¶
| Herramienta | Comando | Señal |
|---|---|---|
gaff | gaff check archivo.c | Regla 0x4003h: rama de error sin perror/strerror. |
gcc | gcc -Wall -Wextra -std=c11 archivo.c | Sin señal directa; requiere revisión. |
cppcheck | cppcheck --enable=all archivo.c | unreadVariable sobre errno o mensajes genéricos. |
Checklist de autocontrol¶
¿Incluí
<errno.h>y<string.h>/<stdio.h>antes de usarlos?¿Reporté el fallo inmediatamente, sin operaciones intermedias?
Si lo reporté más tarde, ¿guardé
errnoen una variable local?¿Envié el diagnóstico a
stderry no astdout?
Reglas relacionadas¶
0x4001h: Manejá correctamente la apertura y cierre de archivos — la apertura fallida es el caso más frecuente de reporte.
0x4002h: Validá los retornos de las operaciones de lectura y escritura de archivos — distinguir EOF de error real requiere
ferror, noerrno.0x4008h: Validación obligatoria del valor de retorno de fclose() en modo escritura — el fallo de
fclosetambién se diagnostica conerrno.0x500Bh: Inclusión obligatoria de cabeceras estándar para funciones de la biblioteca C — inclusión obligatoria de las cabeceras de biblioteca.