ProgrammationDéveloppeur C

Comment la gestion des erreurs est-elle implémentée en C ? Quelles sont les différences entre setjmp/longjmp, errno et le retour de code d'erreur ? Quand utiliser chaque approche ?

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse

En C, il n'y a pas de support intégré pour les exceptions, la gestion des erreurs est réalisée de plusieurs manières :

  1. Retour de code d'erreur (généralement via la valeur de la fonction) Exemple :

    int read_file(const char *name) { FILE *f = fopen(name, "r"); if (!f) return -1; // Erreur // ... fclose(f); return 0; // Succès }
  2. Utilisation de la variable globale errno En cas d'erreur, les fonctions standard définissent souvent la variable globale errno. Exemple :

    FILE *fp = fopen("nofile", "r"); if (!fp) { perror("Erreur de fichier"); // errno définit la raison }
  3. setjmp/longjmp — un mécanisme pour lancer des "exceptions" (le contexte d'exécution est sauvegardé et restauré) Utilisé pour des cas complexes (par exemple, une terminaison anormale entre niveaux). Utilisé rarement car cela complique le code et peut entraîner des fuites de ressources.

    #include <setjmp.h> jmp_buf buf; if (setjmp(buf) == 0) { // ... longjmp(buf, 1); // Revient à if (setjmp(...)) } else { // Gestion d'erreur }
  • Retour de code d'erreur — la méthode principale, simple et sûre.
  • errno — pratique pour les fonctions de bibliothèque.
  • setjmp/longjmp — pour des cas spécifiques (bibliothèques complexes ou interpréteurs).

Question piège

Que va afficher le code suivant ?

#include <stdio.h> #include <setjmp.h> jmp_buf buf; void func() { longjmp(buf, 5); } int main() { int val = setjmp(buf); printf("val=%d\n", val); if (val == 0) func(); return 0; }

Réponse :

  • Lors du premier appel, setjmp retourne 0 et la fonction func est appelée.
  • Dans celle-ci, longjmp(buf, 5) est exécuté, l'exécution revient à setjmp, qui retourne maintenant 5.
  • Sortie finale :
    val=0
    val=5
    

Exemples d'erreurs réelles dues à l'ignorance des subtilités du sujet


Histoire Dans une bibliothèque, un mécanisme manuel de nettoyage des ressources en cas d'erreur a été implémenté uniquement par code de retour. Mais le programmeur a oublié de gérer l'erreur lors d'un retour non pas du fil principal, mais d'un callback (via setjmp/longjmp), ce qui a entraîné des fuites de mémoire et des blocages de fichiers.


Histoire Dans une application réseau, la vérification de errno a été omise après une opération de socket. En conséquence, un faux diagnostic s'est produit : la variable errno a conservé une ancienne valeur incorrecte de la fonction précédente.


Histoire L'équipe a réalisé une complexité d'imbrication avec de nombreux points de retour de code d'erreur, mais n'a pas respecté la convention sur les valeurs de retour (zéro/valeurs négatives). Certaines erreurs étaient interprétées comme réussies, entraînant des défaillances imprévisibles du service.