Der C-Standard schreibt vor, dass keine C-Standardbibliotheksfunktionen errno
auf Null gesetzt werden dürfen. Warum genau ist das so?
Ich könnte verstehen, dass es nützlich ist, mehrere Funktionen aufzurufen und erst errno
nach der letzten zu überprüfen - zum Beispiel:
errno = 0;
double x = strtod(str1, NULL);
long y = strtol(str2, NULL);
if (errno)
// either "strtod" or "strtol" failed
else
// both succeeded
Wird dies jedoch nicht als "schlechte Praxis" angesehen? Da Sie nur sind die Überprüfung errno
am Ende, Sie wissen nur , dass eine der Funktionen haben scheitern, aber nicht die gescheiterten funktionieren. Ist es einfach gut genug zu wissen, dass etwas für die meisten praktischen Programme fehlgeschlagen ist?
Ich habe versucht, nach verschiedenen C Rationale-Dokumenten zu suchen, aber viele von ihnen haben nicht viele Details <errno.h>
.
errno
, können Sie es jederzeit selbst auf Null setzen.errno
auf einen Wert ungleich Null gesetzt werden kann, wenn dies erfolgreich ist. (Es könnte eine andere Funktion aufrufen, die fehlschlägt, aber dies stellt keinen Fehler in der äußeren Funktion dar.)Antworten:
Die C-Bibliothek wird
errno
aus historischen Gründen nicht auf 0 gesetzt 1 . POSIX behauptet nicht mehr, dass seine Bibliotheken den Wert im Erfolgsfall nicht ändern werden, und die neue Linux-Manpage fürerrno.h
spiegelt dies wider:Die ANSI C-Begründung besagt, dass der Ausschuss es für praktischer hielt, die bestehende Verwendungspraxis zu übernehmen und zu standardisieren
errno
.Es gibt fast immer eine Möglichkeit, außerhalb der Überprüfung auf Fehler auf Fehler zu prüfen
errno
. Das Überprüfen, oberrno
gesetzt wurde, ist nicht immer zuverlässig, da für einige Aufrufe eine separate API aufgerufen werden muss, um den Fehlergrund zu ermitteln.ferror()
Wird beispielsweise verwendet, um nach einem Fehler zu suchen, wenn Sie ein kurzes Ergebnis vonfread()
oder erhaltenfwrite()
.Interessanterweise ist Ihr Beispiel für die Verwendung
strtod()
einer der Fälle, in denen die Einstellungerrno
auf 0 vor dem Aufruf erforderlich ist , um korrekt zu erkennen, ob ein Fehler aufgetreten ist. Für allestrto*()
String-to-Number-Funktionen gilt diese Anforderung, da auch bei einem Fehler ein gültiger Rückgabewert zurückgegeben wird.Der obige Code basiert auf dem Verhalten von
strtod()
Linux . Der C-Standard schreibt nur vor, dass der Unterlauf keinen Wert zurückgeben kann, der größer als das kleinste Positiv istdouble
, und ob dieerrno
EinstellungERANGE
festgelegt ist oder nicht, ist in der Implementierung definiert 2 .Tatsächlich gibt es eine umfangreiche Beschreibung der Zertifizierungsempfehlungen, in der empfohlen wird
errno
, vor einem Bibliotheksaufruf immer den Wert 0 festzulegen und den Wert nach dem Aufruf zu überprüfen, um anzuzeigen, dass ein Fehler aufgetreten ist . Dies liegt daran, dass einige Bibliotheksaufrufe auch dann gesetzt werdenerrno
, wenn der Aufruf selbst erfolgreich war 3 .1. Früher habe ich behauptet, es sollte vermieden werden, einen Fehler aus einem früheren Anruf zu maskieren. Ich kann keine Beweise finden, die diese Behauptung stützen. Ich hatte auch ein falsches
printf()
Beispiel.2. Vielen Dank an @chux für diesen Hinweis. Referenz ist C.11 §7.22.1.3 ¶10.
3. In einem Kommentar von @KeithThompson darauf hingewiesen.
quelle
errno
aufERANGE
die Implementierung im Falle eines Unterlaufs definiert ist, gibt es tatsächlich keine tragbare Möglichkeit, einen Unterlauf zu erkennen. Mein Code folgte dem, was ich in der Linux-Manpage auf meinem System gefunden habe.strto*
Funktionen sind genau der Grund, warum ich gefragt habe, ob mein Beispiel als schlechte Praxis angesehen wird, aber es ist die einzige Möglichkeit,errno
nicht auf Null gesetzt zu werden oder sogar anzuwenden.errno
selbst im Erfolgsfall gesetzt werden kann. Die Tatsache, dass er gesetzt wurde, ist also nicht gut genug, um anzuzeigen, dass ein Fehler aufgetreten ist. Sie müssen die Ergebnisse der einzelnen Anrufe selbst überprüfen, um festzustellen, ob überhaupt ein Fehler aufgetreten ist.Sie können für beide Funktionsaufrufe eine Fehlerprüfung durchführen, wenn Sie sich wirklich darum kümmern.
Da wir nie wissen, wie die mach-Funktion in einem Prozess aufgerufen wird, wie kann die lib Fehler für jeden Funktionsaufruf setzen, richtig?
quelle
Das willkürliche Ändern des Errornos ist analog zum "Fangen und Schlucken" einer Ausnahme. Bevor es Ausnahmen gab, die sich über verschiedene Ebenen eines Programms ausbreiteten und schließlich einen Punkt erreichten, an dem der Aufrufer die Ausnahme entweder abfängt und auf irgendeine Weise reagiert oder einfach das Geld übergibt, gab es Fehler. Es ist für dieses Paradigma der Fehlerbehandlung der ersten Generation von wesentlicher Bedeutung, den Fehler nicht zu ändern, es sei denn, Sie behandeln den Fehler irgendwie, überschreiben ihn und behandeln ihn als irrelevant.
quelle