La norme C exige qu'aucune fonction de bibliothèque standard C ne soit mise errno
à zéro. Pourquoi est-ce exactement cela?
Je pourrais comprendre qu'il soit utile d'appeler plusieurs fonctions et de ne vérifier errno
qu'après la dernière - par exemple:
errno = 0;
double x = strtod(str1, NULL);
long y = strtol(str2, NULL);
if (errno)
// either "strtod" or "strtol" failed
else
// both succeeded
Cependant, cela n'est-il pas considéré comme une "mauvaise pratique"? Comme vous ne vérifiez errno
qu'à la toute fin, vous savez seulement qu'une des fonctions a échoué, mais pas la fonction qui a échoué. Le simple fait de savoir que quelque chose a échoué est-il suffisant pour la plupart des programmes pratiques?
J'ai essayé de chercher divers documents de justification C, mais beaucoup d'entre eux n'ont pas beaucoup de détails <errno.h>
.
errno
, vous pouvez toujours le mettre à zéro vous-même.errno
avoir une valeur non nulle même si elle réussit. (Il pourrait appeler une autre fonction qui échoue, mais cela ne constitue pas une défaillance de la fonction extérieure.)Réponses:
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: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
.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 defread()
oufwrite()
.Chose intéressante, votre exemple d'utilisation
strtod()
est l'un des cas où la définitionerrno
de 0 avant l'appel est requise pour détecter correctement si une erreur s'est produite. Toutes les fonctionsstrto*()
chaîne à nombre ont cette exigence, car une valeur de retour valide est renvoyée même en cas d'erreur.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 positifdouble
, et qu'il soiterrno
défini ou non sur la mise enERANGE
œ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éfiniserrno
même si l'appel lui-même a réussi 3 .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.
la source
errno
deERANGE
est l'implémentation définie en cas de sous-dépassement, il n'y a en fait aucun moyen portable de détecter le sous-dépassement. Mon code a suivi ce que j'ai trouvé dans la page de manuel Linux sur mon système.strto*
fonctions sont exactement la raison pour laquelle j'ai demandé si mon exemple serait considéré comme une mauvaise pratique, mais c'est la seule façon deerrno
ne pas être mis à zéro serait utile, ou même s'appliquer.errno
peut être réglé même en cas de succès, donc simplement utiliser le fait qu'il a été défini n'est pas vraiment un assez bon indicateur qu'une erreur s'est produite. Vous devez vérifier les résultats des appels individuels pour savoir si une erreur s'est produite.Vous pouvez faire une vérification d'erreur pour les deux appels de fonction, si vous vous souciez vraiment.
Puisque nous ne savons jamais comment la fonction mach est appelée dans un processus, comment la lib peut-elle définir des errnos pour chaque appel de fonction, n'est-ce pas?
la source
Changer arbitrairement l'errorno est analogue à «attraper et avaler» une exception. Avant qu'il y ait des exceptions qui se propageraient à travers différentes couches d'un programme et atteindraient finalement un point où l'appelant intercepterait et répondrait à l'exception d'une certaine manière ou passerait simplement la balle, il y avait des erreurs. Ne pas modifier l'errno, sauf si vous gérez, remplacez, traitez l'erreur comme non pertinente, est essentiel à ce paradigme de propagation de la gestion des erreurs de première génération.
la source