Gestion d'erreurs en C
Exemples d'erreurs
Fichiers
FILE *file;
file = fopen("tilemap.txt", "r");
if (file == NULL) {
//quelle erreur
return -1; // ou exit(-1)
}
Avec un fichier on peut savoir un stream
est dans un état d'erreur avec :
int ferror( FILE * stream );
qui renvoie en fait un booléen.
Problème de réseau
Cf. cours au 1er semestre
Problème de chargement d'une librairie dynamique
Numéro d'erreurs
Quand il y a une erreur dans une fonction, on a un accès un numéro d'erreurs avec la variable globale errno
disponible avec #include <errno.h>
.
errno == 0
: pas de soucis ✅errno != 0
: il y a eu un problème ❌
Message d'erreur
Aussi, la fonction
char * strerror ( int errCode );
affiche le message d'erreur textuel compréhensible par un humain correspondant à l'erreur. La fonction strerror
est disponible via #include <string.h>
. Typiquement, on appelle :
puts(strerror(errno));
⚠ On ne libère pas la mémoire de la chaîne de caractères d'erreur : free(strerror(errno));
- D'après vous pourquoi on ne libère pas la mémoire d'une chaîne de caractères renvoyés par
strerror
?
Informer l'utilisateur sur la sortie d'erreur
void perror( const char * prefix );
Elle affiche un message d'erreur sur stderr
. Comme stdin
et stdout
qui sont respectivement les flux standards pour l'entrée et la sortie, stderr
est le flux standard pour les erreurs. stderr
est généralement redirigé vers la console, comme stdout
.
Utilisation mot-clé goto
https://github.com/openbsd/src/blob/master/sys/dev/ata/wd.c
setjmp
et longjmp
Devoir gérer les erreurs en cas d'imbrication de fonctions est fastidieux.
En Java, Python, C++, et autres,on a des exceptions pour gérer les erreurs. En C, non, mais il y a setjmp
et longjmp
de <setjmp.h>
.
- Tu poses un jalon pour y revenir plus tard
- Tu exécutes des choses (chargement d'un gros fichier par exemple)
- Tu tombes sur une erreur en croisant un ours
- Tu reviens au jalon et tu affiches un message d'erreur, tu libères la mémoire et tu reviens dans une situation stable
int setjmp(jmp_buf env);
setjmp
pose un jalon 🚩. Elle écrit dans env
les données relatives au contexte de la pile d'appel actuel. Cette fonction renvoie 0... sauf que...
void longjmp(jmp_buf env, int value);
longjmp
renvoie au jalon avec le contexte de l'époque. On renvoie dans le code où il y avait l'appel à setjmp
qui maintenant renvoie value
(qui doit être différente de 0).
#include <stdio.h>
#include <setjmp.h>
static jmp_buf jmpBuffer;
void b() {
...
if(error) {
longjmp(jmpBuffer, 1);
}
}
void a() {
b();
}
void bigComputation() {
a();
}
int main() {
if (setjmp(jmpBuffer) == 0)
bigComputation();
else
printf("désolé il y a eu une erreur\n");
return EXIT_SUCCESS;
}
Exemple d'utilisation : https://sourceforge.net/p/libpng/code/ci/master/tree/example.c#l322