ProgrammazioneSviluppatore Backend C

Come realizzare la gestione degli errori quando si lavora con le funzioni della libreria standard C? Qual è la specificità dell'uso di errno, quando è meglio usare i codici di ritorno e come evitare errori nella gestione?

Supera i colloqui con l'assistente IA Hintsage

Risposta.

Storia della domanda

La gestione degli errori nel linguaggio C è sempre stata compito dello sviluppatore. Nella libreria standard non ci sono eccezioni, gli errori vengono restituiti tramite codici di ritorno o una variabile globale errno (inizio utilizzo – UNIX anni '70, poi POSIX e ANSI C). Tali meccanismi sono usati anche oggi per gestire il flusso di esecuzione in situazioni anomale.

Problema

Gli errori nel lavoro con le funzioni standard (operazioni su file, allocazione di memoria, funzioni di stringa) possono passare inosservati senza un controllo specifico. Un'elaborazione errata – ignorare il codice di ritorno, interpretare erroneamente errno, non liberare le risorse – porta a un funzionamento scorretto del programma, crash e vulnerabilità.

Soluzione

Una corretta gestione degli errori richiede un'analisi obbligatoria dei valori restituiti dalle funzioni, l'uso di errno solo subito dopo un fallimento e un'uscita informativa degli errori. I codici di ritorno sono preferibili per le funzioni interne – consentono una gestione senza effetti collaterali globali. errno è usato più frequentemente con le chiamate di sistema e le funzioni della libreria standard. Dopo ogni operazione potenzialmente pericolosa viene analizzato il ritorno, e lo stato globale (errno) non deve essere sovrascritto da chiamate intermedie.

Esempio di codice:

#include <stdio.h> #include <errno.h> #include <string.h> FILE *open_file(const char *filename) { errno = 0; FILE *f = fopen(filename, "r"); if (!f) { fprintf(stderr, "Errore: %s ", strerror(errno)); } return f; }

Caratteristiche chiave:

  • errno è utilizzato solo per diagnosticare errori verificatisi in chiamate di sistema/funzioni standard.
  • È comodo restituire codici di errore int all'interno delle funzioni, zero è successo, numeri negativi o valori speciali sono fallimenti.
  • È importante non fare affidamento sul valore di errno se prima non si è verificato un errore.

Domande trabocchetto.

Si può utilizzare errno per funzioni utente, se si vuole passare gli errori verso l'alto?

No, errno è destinata solo a chiamate di libreria standard e di sistema. È globale, può essere sovrascritta in qualsiasi punto e non è adatta per le proprie funzioni.

È obbligatorio impostare errno prima di ogni chiamata di funzione?

No, ma si raccomanda di azzerare errno (ad esempio, a zero) prima delle chiamate, se si intende analizzare le modifiche. Non ogni funzione modifica errno al successo, ma solo in caso di errore.

errno = 0; ... chiamata funzione pericolosa ...

Si può fare affidamento su errno dopo qualsiasi funzione?

Solo per quelle funzioni che secondo lo standard la impostano esplicitamente in caso di fallimento. Molte funzioni della libreria standard non toccano errno in caso di successo. La documentazione è la tua amica.

Errori comuni e anti-pattern

  • Ignorare il codice di ritorno di funzioni (ad esempio, fopen, malloc, write).
  • Sovrascrivere errno prima di utilizzare il suo valore.
  • Utilizzare errno per i propri errori nel progetto.

Esempio nella vita reale

Caso negativo

Apertura di un file senza controllare il risultato, gli errori non vengono analizzati, il programma funziona in modo errato in assenza del file:

Vantaggi:

  • Meno codice, funziona rapidamente in casi semplici.

Svantaggi:

  • Crash criptici in caso di errori, impossibilità di diagnosi.

Caso positivo

Dopo ogni funzione critica il risultato viene controllato, in caso di errore viene restituito un messaggio dettagliato con strerror(errno), l'esecuzione termina correttamente:

Vantaggi:

  • Il programma è facile da manutenere e debuggare, alta stabilità.

Svantaggi:

  • Un po' più di codice, leggermente più complessità.