La bibliothèque C n'est pas définie errno
sur 0 pour des raisons historiques 1 . POSIX ne prétend plus que ses bibliothèques ne modifieront pas la valeur en cas de succès, et la nouvelle page de manuel Linux pour leerrno.h
reflète:
Le <errno.h>
fichier d'en-tête définit la variable entière errno
, qui est définie par les appels système et certaines fonctions de bibliothèque en cas d'erreur pour indiquer ce qui n'a pas fonctionné. Sa valeur n'est significative que lorsque la valeur de retour de l'appel indique une erreur (c'est-à-dire -1
de la plupart des appels système -1
ou NULL
de la plupart des fonctions de bibliothèque); une fonction qui réussit peut changer errno
.
La justification de l'ANSI C indique que le comité a estimé qu'il était plus pratique d'adopter et de normaliser la pratique actuelle d'utilisation errno
.
Le mécanisme de rapport d'erreurs centré sur le réglage de errno
est généralement considéré avec la tolérance au mieux. Il nécessite un `` couplage pathologique '' entre les fonctions de bibliothèque et utilise une cellule de mémoire inscriptible statique, ce qui interfère avec la construction de bibliothèques partageables. Néanmoins, le Comité a préféré standardiser ce mécanisme existant, quoique déficient, plutôt que d'inventer quelque chose de plus ambitieux.
Il existe presque toujours un moyen de vérifier les erreurs en dehors de la vérification si elles errno
sont définies. Vérifier si l' errno
ensemble obtenu n'est pas toujours fiable, car certains appels nécessitent d'appeler une API distincte pour obtenir la raison de l'erreur. Par exemple, ferror()
est utilisé pour rechercher une erreur si vous obtenez un résultat court à partir de fread()
ou fwrite()
.
Chose intéressante, votre exemple d'utilisation strtod()
est l'un des cas où la définition errno
de 0 avant l'appel est requise pour détecter correctement si une erreur s'est produite. Toutes les fonctions strto*()
chaîne à nombre ont cette exigence, car une valeur de retour valide est renvoyée même en cas d'erreur.
errno = 0;
char *endptr;
double x = strtod(str1, &endptr);
if (endptr == str1) {
/*...parse error */
} else if (errno == ERANGE) {
if (x == 0) {
/*...underflow */
} else if (x == HUGE_VAL) {
/*...positive overflow */
} else if (x == -HUGE_VAL) {
/*...negative overflow */
} else {
/*...unknown range error? */
}
}
Le code ci-dessus est basé sur le comportement de strtod()
tel que documenté sur Linux . La norme C stipule uniquement que le sous-dépassement ne peut pas renvoyer une valeur supérieure au plus petit positif double
, et qu'il soit errno
défini ou non sur la mise en ERANGE
œuvre définie 2 .
Il existe en fait un compte rendu complet des avis de certification qui recommande de toujours définir la valeur errno
0 avant un appel à la bibliothèque et de vérifier sa valeur après l'appel indique qu'une défaillance s'est produite . En effet, certains appels de bibliothèque sont définis errno
même si l'appel lui-même a réussi 3 .
La valeur de errno
est 0 au démarrage du programme, mais elle n'est jamais définie sur 0 par aucune fonction de bibliothèque. La valeur de errno
peut être définie sur non nulle par un appel de fonction de bibliothèque, qu'il y ait ou non une erreur, à condition que l'utilisation de errno
ne soit pas documentée dans la description de la fonction dans la norme C. Il est important pour un programme d'inspecter le contenu errno
uniquement après qu'une erreur a été signalée. Plus précisément, errno
n'a de sens qu'après qu'une fonction de bibliothèque qui se déclenche errno
sur erreur a renvoyé un code d'erreur.
1. Auparavant, je prétendais que c'était pour éviter de masquer une erreur d'un appel précédent. Je ne trouve aucune preuve à l'appui de cette affirmation. J'ai également eu un faux printf()
exemple.
2. Merci à @chux de l'avoir signalé. La référence est C.11 §7.22.1.3 ¶10.
3. Signalé par @KeithThompson dans un commentaire.
errno
, vous pouvez toujours le mettre à zéro vous-même.