ProgrammationDéveloppeur Backend C

Comment mettre en œuvre la gestion des erreurs lors de l'utilisation des fonctions de la bibliothèque standard C ? Quelle est la spécificité de l'utilisation d'errno, quand est-il préférable d'utiliser les codes de retour et comment éviter les erreurs lors du traitement ?

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse.

Historique de la question

La gestion des erreurs en langage C a toujours été la tâche du développeur. La bibliothèque standard ne dispose pas d'exceptions, les erreurs sont retournées par des codes de retour ou une variable globale errno (utilisation initiale — UNIX des années 1970, puis POSIX et ANSI C). De tels mécanismes sont encore utilisés aujourd'hui pour gérer le flux d'exécution en cas de situations imprévues.

Problème

Les erreurs lors de l'utilisation des fonctions standard (opérations sur les fichiers, allocation de mémoire, fonctions sur les chaînes) peuvent passer inaperçues sans contrôle particulier. Un traitement incorrect — ignorer le code de retour, mal interpréter errno, négliger le nettoiement des ressources — conduit à un fonctionnement erroné du programme, à des plantages et à des vulnérabilités.

Solution

Un traitement correct des erreurs nécessite une analyse obligatoire des valeurs retournées par les fonctions, l'utilisation d'errno uniquement immédiatement après une erreur, et un affichage informatif des erreurs. Les codes de retour sont préférables pour les fonctions internes — ils permettent une gestion sans effets secondaires globaux. errno est plus souvent utilisé avec des appels système et des fonctions de la bibliothèque standard. Après chaque opération potentiellement dangereuse, le retour est analysé, et l'état global (errno) ne doit pas être écrasé par des appels intermédiaires.

Exemple de code :

#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, "Erreur : %s ", strerror(errno)); } return f; }

Caractéristiques clés :

  • errno est utilisé uniquement pour le diagnostic des erreurs survenant dans des appels système/fonctions standard.
  • Dans les fonctions, il est pratique de retourner des codes d'erreur int, zéro — succès, nombre négatif ou valeurs spéciales — échec.
  • Il est important de ne pas se fier à la valeur d'errno si aucune erreur ne s'est produite auparavant.

Questions piégeuses.

Peut-on utiliser errno pour des fonctions utilisateur si l'on souhaite faire remonter les erreurs ?

Non, errno est réservée aux bibliothèques standard et aux appels système. Elle est globale, peut être écrasée à tout moment et n'est pas adaptée pour vos propres fonctions.

Est-il obligatoire de réinitialiser errno avant chaque appel de fonction ?

Non, mais il est recommandé de réinitialiser errno (par exemple à zéro) avant les appels, si l'on prévoit d'analyser les modifications. Toutes les fonctions ne modifient pas errno en cas de succès, mais uniquement en cas d'erreur.

errno = 0; ... appel d'une fonction dangereuse ...

Peut-on faire confiance à errno après n'importe quelle fonction ?

Seulement pour celles qui, selon les normes, définissent explicitement errno en cas d'échec. De nombreuses fonctions de la bibliothèque standard ne touchent pas errno en cas de succès. La documentation est votre amie.

Erreurs typiques et anti-patrons

  • Ignorer le code de retour des fonctions (par exemple, fopen, malloc, write).
  • Écraser errno avant de l'utiliser.
  • Utiliser errno pour ses propres erreurs dans le projet.

Exemple de la vie réelle

Cas négatif

Ouverture d'un fichier sans vérification du résultat, les erreurs ne sont pas analysées, le programme fonctionne incorrectement en l'absence de fichier :

Avantages :

  • Moins de code, fonctionne rapidement dans des scénarios simples.

Inconvénients :

  • Pannes cryptiques en cas d'erreurs, difficulté à diagnostiquer.

Cas positif

Après chaque fonction critique, le résultat est vérifié, en cas d'erreur, un message détaillé avec strerror(errno) est affiché, l'exécution se termine correctement :

Avantages :

  • Le programme est facile à maintenir et à déboguer, haute stabilité.

Inconvénients :

  • Un peu plus de code, une complexité légèrement accrue.