Lección 17 · 17 de 20
Errores: códigos de retorno y errno · C
Gestione errores en C con códigos de retorno propios, errno, strtol y strerror: validar cantidades de un pedido y avisar si falta un archivo.

C no tiene excepciones: cada función avisa de un fallo con lo que devuelve. La forma más clara es un enum de códigos de retorno, como Status, y dejar el resultado en un parámetro de salida: parse_quantity devuelve OK o un error, y solo si todo va bien escribe la cantidad en *out; por eso, en la salida, qty sigue a 0 en las entradas con error. status_text traduce cada código a un mensaje fijo.
`strtol` convierte texto en long y, en end, deja un puntero al primer carácter que no ha podido leer. Si end == text no había ningún número (abc); si *end no es '\0', sobra algo detrás (12kg). Es mucho más seguro que atoi, que con abc devuelve 0 sin decir nada.
`errno`, de errno.h, es una variable global donde la biblioteca estándar anota el último error. Solo se escribe cuando algo falla, así que hay que ponerla a 0 antes de llamar a strtol y mirarla justo después: ERANGE significa que el número no cabe en un long, como 99999999999999999999.
fopen también deja la causa en errno cuando devuelve NULL, y `strerror(errno)` la convierte en texto: «No such file or directory». `perror("texto")` hace lo mismo en una sola llamada, pero escribe en la salida de errores (stderr).
main termina con EXIT_SUCCESS; un programa que falla devuelve EXIT_FAILURE, y es lo que ven los scripts que lo ejecutan. En DMarlon Studio el destino Consola muestra la salida al ejecutar con F9.
Código · main.c
#include <errno.h>#include <stdio.h>#include <stdlib.h>#include <string.h>// Return codes: the function reports what happened; the result goes in *out.typedef enum { OK, ERR_EMPTY, ERR_NOT_NUMBER, ERR_RANGE } Status;const char *status_text(Status s) { static const char *texts[] = {"ok", "empty text", "not a whole number", "out of range"}; return texts[s];}Status parse_quantity(const char *text, long *out) { if (*text == '\0') return ERR_EMPTY; char *end; errno = 0; // strtol only sets errno when it fails long value = strtol(text, &end, 10); if (end == text || *end != '\0') return ERR_NOT_NUMBER; // "12kg": end points at k if (errno == ERANGE || value < 1 || value > 500) return ERR_RANGE; *out = value; return OK;}int main(void) { const char *inputs[] = {"25", "", "12kg", "abc", "99999999999999999999", "0"}; for (int i = 0; i < 6; i++) { long qty = 0; Status st = parse_quantity(inputs[i], &qty); printf("%-22s %s (%ld)\n", *inputs[i] ? inputs[i] : "(empty)", status_text(st), qty); } FILE *f = fopen("missing-orders.csv", "r"); // the standard library uses errno if (f == NULL) printf("Cannot open missing-orders.csv: %s\n", strerror(errno)); else fclose(f); return EXIT_SUCCESS;}Salida · cc main.c -o main && ./main
25 ok (25) (empty) empty text (0) 12kg not a whole number (0) abc not a whole number (0) 99999999999999999999 out of range (0) 0 out of range (0) Cannot open missing-orders.csv: No such file or directory
Para recordar
- Devuelva un código de estado y deje el resultado en un puntero.
strtolconenddetecta texto vacío o sobrante.- Ponga
errno = 0antes de la llamada y mírelo justo después. strerror(errno)yperrorexplican el error del sistema.
Ejercicio
Añada "-3" a las entradas y el código ERR_NEGATIVE para que esa entrada dé «negative quantity» en vez de «out of range», y haga que main devuelva EXIT_FAILURE si alguna entrada no es válida.