Quand dois-je utiliser perror («…») et fprintf (stderr, «…»)?

105

La lecture des pages de manuel et du code ne m'a pas vraiment aidé à comprendre la différence entre - ou mieux, quand je devrais utiliser - perror("...")ou fprintf(stderr, "...").

freeboy1015
la source

Réponses:

113

L'appel perrorvous donnera la valeur interprétée de errno, qui est une valeur d'erreur locale au thread écrite par les appels système POSIX (c'est-à-dire que chaque thread a sa propre valeur pour errno). Par exemple, si vous avez fait un appel à open(), et qu'une erreur s'est produite (c'est-à-dire qu'elle est retournée -1), vous pouvez alors appeler perrorimmédiatement après pour voir quelle était l'erreur réelle. Gardez à l'esprit que si vous appelez d'autres appels système entre-temps, la valeur de errnosera écrasée et l'appel perrorne sera d'aucune utilité pour diagnostiquer votre problème si une erreur a été générée par un appel système antérieur.

fprintf(stderr, ...)d'autre part, peut être utilisé pour imprimer vos propres messages d'erreur personnalisés. En imprimant vers stderr, vous évitez que votre sortie de rapport d’erreurs soit mélangée avec la sortie «normale» qui devrait aller vers stdout.

Gardez à l'esprit que cela fprintf(stderr, "%s\n", strerror(errno))est similaire à perror(NULL)car un appel à strerror(errno)générera la valeur de chaîne imprimée pour errno, et vous pouvez ensuite combiner cela avec tout autre message d'erreur personnalisé via fprintf.

Jason
la source
3
Oh, compris, la fonction perror fonctionne différemment selon la valeur de errno. If you use a function that effects errno then it makes sense to use perrorSi vous utilisez une fonction qui n'effectue pas errno et renvoie simplement un code d'erreur, vous devez utiliser fprintf (stderr, fmt, ...). Par exemple, strtol retournera LONG_MAX ou LONG_MIN si une chaîne est hors de portée et définira errno sur ERANGE. Donc, si strtol échoue en raison d'un hors de portée, j'utiliserais perror.
freeboy1015
6
Un détail strerrorn'est pas nécessaire pour être thread-safe. C'est stupide, mais c'est la norme. strerror_lpeut être utilisé à la place en remplacement instantané sur les systèmes POSIX 2008. strerror_rest également disponible sur les systèmes plus anciens, mais présente des problèmes vraiment désagréables avec certains systèmes ayant des versions non conformes.
R .. GitHub STOP HELPING ICE
aussi comme un nitpick, je pense que perrorajoute '\n'à la fin donc le format serait "%s\n", non?
Jens Gustedt
1
@R .., ha, je l'ai déjà fait, et pour autant que je sache, ils ne me paient rien. Et comme MS semble couper complètement leur support pour C, à la fin je serai le seul :) strerror_sn'est en fait pas trop mal comme interface.
Jens Gustedt
2
Couper complètement le support? On dirait qu'ils ont encore une fois trompé le comité. Faire _sentrer leurs déchets dans la norme était essentiellement un jeu de MS ("Si vous adoptez nos interfaces, nous envisagerons de faire en sorte que nos produits prennent en charge votre norme.") Et bien sûr, maintenant, ils ne respectent pas. En fait, je suis d'accord que cette interface n'est pas mauvaise en soi. Ce qui est mauvais, c'est la propagande (sous forme d'avertissements du compilateur) selon laquelle la plupart de la bibliothèque standard est "non sécurisée" et que toute la famille de _sfonctions devrait être utilisée à la place des fonctions standard.
R .. GitHub STOP HELPING ICE
40

Ils font des choses assez différentes.

Vous utilisez perror()pour imprimer un message stderrcorrespondant à errno. Vous utilisez fprintf()pour imprimer quoi que ce soit sur stderr, ou tout autre flux. perror()est une fonction d'impression très spécialisée:

perror(str);

est équivalent à

if (str)
    fprintf(stderr, "%s: %s\n", str, strerror(errno));
else
    fprintf(stderr, "%s\n", strerror(errno));
freeboy1015
la source
12

perror(const char *s): imprime la chaîne que vous lui donnez suivie d'une chaîne qui décrit la valeur actuelle de errno.

stderr: c'est un flux de sortie utilisé pour diriger vos propres messages d'erreur vers (par défaut vers le terminal).

Pertinent:

char *strerror(int errnum): donnez-lui un numéro d'erreur et il renverra la chaîne d'erreur associée.

Adib Saad
la source
2

perror () écrit toujours dans stderr; strerr (), utilisé avec fprintf (), peut écrire sur n'importe quelle sortie - y compris stderr mais pas exclusivement.

fprintf(stdout, "Error: %s", strerror(errno));
fprintf(stderr, "Error: %s", strerror(errno)); // which is equivalent to perror("Error")

De plus, perror impose son propre formatage de texte "texte: description d'erreur"

Sébastien
la source
-2

La fonction Perror prend plus de temps pour exécuter l'appel d'exécution passe de l'espace utilisateur à l'espace noyau, alors que les appels fprintf vont de l'api à kernal

vivek singh
la source