Wann sollte ich perror ("...") und fprintf (stderr, "...") verwenden?

105

Das Lesen der Manpages und eines Codes hat mir nicht wirklich geholfen, den Unterschied zwischen - oder besser, wann ich es verwenden sollte - perror("...")oder zu verstehen fprintf(stderr, "...").

freeboy1015
quelle

Antworten:

113

Der Aufruf perrorwird Ihnen das interpretiert Wert errno, der einen lokalen Thread-Fehlerwert von POSIX syscalls geschrieben ist (dh jeder Thread für seinen eigenen Wert hat errno). Wenn Sie beispielsweise einen Anruf getätigt open()haben und ein Fehler generiert wurde (dh zurückgegeben wurde -1), können Sie perrorsofort danach anrufen , um den tatsächlichen Fehler zu ermitteln. Beachten Sie, dass beim Aufrufen anderer Systemaufrufe in der Zwischenzeit der Wert in überschrieben errnowird und das Aufrufen perrorbei der Diagnose Ihres Problems nicht hilfreich ist, wenn ein Fehler durch einen früheren Systemaufruf generiert wurde.

fprintf(stderr, ...)Auf der anderen Seite können Sie Ihre eigenen benutzerdefinierten Fehlermeldungen drucken. Durch Drucken auf stderrvermeiden Sie, dass Ihre Fehlerberichtsausgabe mit der "normalen" Ausgabe gemischt wird, die verwendet werden soll stdout.

Beachten Sie, dass dies fprintf(stderr, "%s\n", strerror(errno))ähnlich ist, perror(NULL)da ein Aufruf von strerror(errno)den gedruckten Zeichenfolgenwert für generiert errnound Sie diesen dann mit jeder anderen benutzerdefinierten Fehlermeldung über kombinieren können fprintf.

Jason
quelle
3
Oh, verstanden. Die Perror-Funktion funktioniert je nach Wert von errno unterschiedlich. If you use a function that effects errno then it makes sense to use perrorWenn Sie eine Funktion verwenden, die errno nicht beeinflusst und einfach einen Fehlercode zurückgibt, sollten Sie fprintf (stderr, fmt, ...) verwenden. Beispielsweise gibt strtol LONG_MAX oder LONG_MIN zurück, wenn eine Zeichenfolge außerhalb des Bereichs liegt, und setzt errno auf ERANGE. Wenn strtol aufgrund eines Bereichs außerhalb des Bereichs fehlschlägt, würde ich perror verwenden.
freeboy1015
6
Ein Detail muss strerrornicht threadsicher sein. Es ist dumm, aber das ist der Standard. strerror_lkann stattdessen als Drop-In-Ersatz auf POSIX 2008-Systemen verwendet werden. strerror_rist auch auf älteren Systemen verfügbar, hat jedoch bei einigen Systemen mit nicht konformen Versionen wirklich schlimme Probleme.
R .. GitHub STOP HELPING ICE
Auch als Nitpick, denke ich, perrorfügt '\n'am Ende hinzu, so dass das Format wäre "%s\n", nein?
Jens Gustedt
1
@R .., ha, das habe ich schon, und soweit ich weiß, zahlen sie mir nichts. Und da MS ihre Unterstützung für C komplett zu kürzen scheint, werde ich am Ende der einzige sein :) strerror_sist eigentlich keine schlechte Schnittstelle.
Jens Gustedt
2
Schneidunterstützung komplett? Sieht so aus, als hätten sie das Komitee wieder betrogen. Ihren _sMüll in den Standard zu bringen, war im Grunde ein Spiel von MS ("Wenn Sie unsere Schnittstellen übernehmen, werden wir in Betracht ziehen, unsere Produkte tatsächlich dazu zu bringen, Ihren Standard zu unterstützen.") Und natürlich folgen sie jetzt nicht mehr. Eigentlich stimme ich zu, dass diese eine Schnittstelle an sich nicht schlecht ist. Was schlecht ist, ist die Propaganda (in Form von Compiler-Warnungen), dass der größte Teil der Standardbibliothek "unsicher" ist und dass die gesamte _sFunktionsfamilie anstelle der Standardfunktionen verwendet werden sollte.
R .. GitHub STOP HELPING ICE
40

Sie machen ziemlich unterschiedliche Dinge.

Sie verwenden perror(), um eine Nachricht zu drucken, stderrdie entspricht errno. Sie verwenden fprintf()drucken etwas zu stderroder über anderen Strom. perror()ist eine sehr spezielle Druckfunktion:

perror(str);

ist äquivalent zu

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

perror(const char *s): Gibt die Zeichenfolge aus, die Sie ihm geben, gefolgt von einer Zeichenfolge, die den aktuellen Wert von beschreibt errno.

stderr: Es ist ein Ausgabestream, an den Sie Ihre eigenen Fehlermeldungen weiterleiten (standardmäßig an das Terminal).

Relevant:

char *strerror(int errnum): Geben Sie eine Fehlernummer ein, und die zugehörige Fehlerzeichenfolge wird zurückgegeben.

Adib Saad
quelle
2

perror () schreibt immer in stderr; strerr () kann zusammen mit fprintf () in jede Ausgabe schreiben - einschließlich stderr, aber nicht ausschließlich.

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

Darüber hinaus legt perror einen eigenen Text fest, der "text: error description" formuliert.

Sebastien
quelle
-2

Die Perror-Funktion benötigt mehr Zeit, um einen Ausführungsaufruf auszuführen, der vom Benutzerbereich zum Kernalbereich wechselt, während fprintf-Aufrufe von API zu Kernal gehen

vivek singh
quelle