errno, perror și strerror în C

errno păstrează codul ultimei erori a unei funcții de bibliotecă; perror și strerror îl transformă într-un mesaj citibil.

Sintaxă
#include <errno.h>
extern int errno;          // de fapt un macro

#include <stdio.h>
void perror(const char *s);

#include <string.h>
char *strerror(int cod);

Ce face errno, perror și strerror

Multe funcții din biblioteca standard semnalează o eroare printr-o valoare specială (NULL, -1, EOF) și pun motivul în errno, un număr declarat în <errno.h>. Codurile au nume: ENOENT (fișierul nu există), EACCES (acces interzis), ERANGE (rezultat în afara intervalului), EDOM (argument în afara domeniului).

perror("text") scrie pe stderr textul tău, două puncte și descrierea erorii. strerror(cod) returnează descrierea ca șir, ca s-o pui unde vrei (într-un printf, într-un jurnal). Mesajele sunt în engleză și pot diferi puțin între sisteme.

Citește errno imediat după funcția care a eșuat: orice alt apel de bibliotecă îl poate schimba. Funcțiile nu pun errno pe 0 când reușesc, de aceea, la funcții ca strtol, setezi tu errno = 0 înainte de apel.

Parametri

Parametru Descriere
s La perror: textul afișat înaintea mesajului (de obicei numele fișierului sau al operației).
cod La strerror: un cod de eroare, de obicei errno.

Ce returnează

strerror: un șir cu descrierea erorii (nu îl modifica). perror nu returnează nimic.

Exemple

Exemplul 1: Motivul pentru care fopen a eșuat

Fișierul nu există, deci errno devine ENOENT. strerror dă textul pe stdout, iar perror scrie pe stderr (afișat aici la final, după ieșirea normală).

#include <errno.h>
#include <stdio.h>
#include <string.h>

int main(void) {
    FILE *f = fopen("comenzi-iasi.txt", "r");
    if (f == NULL) {
        int cod = errno;
        printf("errno = %d, ENOENT? %s\n", cod, cod == ENOENT ? "da" : "nu");
        printf("strerror: %s\n", strerror(cod));
        perror("comenzi-iasi.txt");
        return 0;
    }
    fclose(f);
    return 0;
}

Rezultat

errno = 2, ENOENT? da
strerror: No such file or directory
comenzi-iasi.txt: No such file or directory

Exemplul 2: errno = 0 înainte de strtol

Un număr prea mare pentru long nu produce o valoare negativă specială: strtol returnează LONG_MAX și pune ERANGE în errno. Ca să știi sigur că eroarea vine de la acest apel, pui errno pe 0 înainte.

#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void) {
    const char *texte[] = {"2500", "99999999999999999999999"};
    for (int i = 0; i < 2; i++) {
        errno = 0;
        long valoare = strtol(texte[i], NULL, 10);
        if (errno == ERANGE) {
            printf("%s: %s (am primit %s)\n", texte[i], strerror(errno),
                   valoare == LONG_MAX ? "LONG_MAX" : "altă valoare");
        } else {
            printf("%s: ok, %ld\n", texte[i], valoare);
        }
    }
    return 0;
}

Rezultat

2500: ok, 2500
99999999999999999999999: Result too large (am primit LONG_MAX)

Greșeli frecvente

  • Verifici errno fără ca funcția să fi raportat o eroare. errno poate avea o valoare veche de la un apel anterior; uită-te la el doar după ce valoarea returnată arată eșecul.
  • Apelezi printf între funcția care a eșuat și citirea lui errno. printf poate modifica errno; salvează-l întâi într-o variabilă.
  • Declari singur int errno;. errno este un macro definit de bibliotecă (fiecare fir de execuție are propria valoare); include doar <errno.h>.

Comenzi înrudite

  • fopen și fclose: Deschide un fișier pentru citire, scriere sau adăugare și returnează un FILE *; fclose îl închide și salvează datele rămase.
  • strtol și strtod: Transformă text în număr și îți spune unde s-a oprit citirea și dacă valoarea a depășit limitele.
  • fprintf: Scrie text formatat într-un fișier sau în stderr, cu același șablon ca printf.
  • exit, atexit și EXIT_SUCCESS: Oprește programul din orice funcție, cu un cod de ieșire; atexit înregistrează funcții de rulat la final.
  • assert: Verifică în timpul rulării o condiție care trebuie să fie mereu adevărată și oprește programul cu un mesaj dacă nu este.