Ich schreibe eine Funktion in C. Als eine Frage des Stils, wann ist es besser,asserting im Vergleich zur Rückgabe eines Fehlercodes zu verwenden. Nehmen wir an, die Funktion dividiert zwei Zahlen. Soll ich behaupten, dass der Divisor ungleich Null ist, oder soll ich einen Fehlercode zurückgeben? Bitte geben Sie, wenn möglich, weitere Beispiele an, um die Unterscheidung deutlich zu machen.
Wann sollten wir Asserts in C verwenden?
Fred Fu
assert
bricht den Prozess ab, wird aber zu einem No-Op, wenn das Programm mit kompiliert wird -DNDEBUG
, also ist es ein ziemlich grobes Debugging-Tool und nicht mehr als das. Sie sollten nur verwenden assert
um nach Situationen zu suchen, die “nicht passieren können”, zB die die Invarianten oder Nachbedingungen eines Algorithmus verletzen, aber wahrscheinlich nicht zur Eingabevalidierung (sicherlich nicht in Bibliotheken). Wenn Sie ungültige Eingaben von Clients erkennen, seien Sie freundlich und geben Sie einen Fehlercode zurück.
Ein Beispiel für die Verwendung von assert
könnte sein: Sie haben einen unglaublich intelligenten Sortieralgorithmus implementiert und möchten überprüfen, ob er wirklich sortiert. Da die Sortierfunktion “einfach funktionieren” soll und daher keinen Wert zurückgibt, können Sie keine Fehlerrückgaben hinzufügen, ohne die API zu ändern.
void sort(int *a, size_t n)
{
recursive_super_duper_sort(a, 0, n);
assert(is_sorted(a, n));
}
static bool is_sorted(int const *a, size_t n)
{
for (size_t i=0; i<n-1; i++)
if (a[i] > a[i+1])
return false;
return true;
}
Auf lange Sicht würden Sie stattdessen lieber ein geeignetes Unit-Testing-Framework für diese Art von Dingen benötigen assert
aber es ist als temporäres Debugging-Tool nützlich.
Kerrek SB
Ein Fehlercode signalisiert Laufzeitverhalten. Eine Assertion ist ein Debugging-Tool, mit dem der Entwickler behaupten kann, dass seine Annahmen über die Programmlogik sind in der Tat wahr.
Das sind zwei völlig verschiedene Dinge mit unterschiedlichen Anwendungen.
Fehlercodes sind Teil Ihres normalen Programmablaufs. Behauptungen sind nur zum Debuggen, und wenn eine Assertion ausgelöst wird, bedeutet dies, dass Ihr Programm nicht korrekt geschrieben ist.
Im Allgemeinen dienen Asserts dem Programmierer (dh Ihnen) dazu, Logik-/Programmierfehler zu finden, bevor er das Programm für echte Benutzer freigibt. Asserts sollten nicht zum Erkennen von Eingabefehlern zur Laufzeit verwendet werden – verwenden Sie dafür Fehlercodes.
Das ist wirklich Geschmackssache. Hier ist meine Meinung.
Die wichtigste Faustregel: ein Behauptungsfehler ist stets ein Fehler im Programm.
Benutze ein assert
um Funktionsparameter zu überprüfen, wenn Sie erwarten, dass der Aufrufer sicherstellt, dass das Argument korrekt ist, und Sie angeben möchten, dass jedes andere Verhalten ein Fehler im Aufrufer ist. Das Teilen durch Null ist meiner Meinung nach ein sehr gutes Beispiel.
Verwenden Sie einen Fehlercode, wenn Sie davon ausgehen, dass der Aufrufer vor dem Aufrufen nicht sicherstellen kann, dass das Argument korrekt ist. Beispielsweise könnte es sehr rechenintensiv sein, die Argumente vorher zu prüfen.
Niemals benutze ein assert
Benutzereingaben zu überprüfen.
Die herkömmliche Weisheit besteht darin, assert() zu verwenden, um Ihren Code zu debuggen, um Sie zu warnen, wenn etwas “Unmögliches”, etwas, das nicht passieren darf, passiert ist. Diese “Warnung” hat die Form, dass Sie Ihr Programm beenden.
Ich habe gehört, dass Jim Coplien (allgemeiner C++-Guru und SCRUM-Trainer) dafür plädiert, Ihre Asserts im bereitgestellten Code aktiv zu lassen. (Es klingt verrückt, ich weiß …) Dies war speziell für hochzuverlässigen Servercode. Die Motivation war, dass es besser ist, hart zu scheitern und einen anderen Knoten übernehmen zu lassen, als zu tolerieren, dass sich Ihr Server in einem “unmöglichen” Zustand befindet.
(Und natürlich die Fehler verfolgen und analysieren. Das bedeutet, dass ein Fehler oder eine falsche Annahme vorliegt.)
Basile Starynkevitch
Zuerst, assert
von dem <assert.h>
Header kann deaktiviert werden (z. B. durch Kompilieren mit gcc -DNDEBUG
) und ist manchmal für die “Produktions”-Version einer Binärdatei deaktiviert.
Zweitens, wie auf der Linux-Manpage angegeben,
The purpose of this macro is to help the programmer find bugs in his
program. The message "assertion failed in file foo.c, function
do_bar(), line 1287" is of no help at all to a user.
Assert sollte also nur in Buggy-Situationen fehlschlagen. In Ausnahme- oder Fehlersituationen sollten Sie etwas anderes tun.
Einige Tools (oder sogar Compiler) verwenden möglicherweise assert
-ions, um zB Ihren Code zu optimieren.
In deinem Beispiel von a quotient
Funktion, die Sie verwenden assert
wenn Sie in Ihrem gesamten Programm sicher sind, dass der Divisor ungleich Null sein sollte (aber dann könnte es sinnvoll sein, die Funktion vielleicht anders zu benennen quotient_by_non_zero
). Wenn Sie der Meinung sind, dass dies passieren könnte, machen Sie daraus eine schwerwiegende Nachricht, eine Ausnahme (z longjmp
in C), einen Fehlercode usw.
David Heffernan
Da C keine Ausnahmen unterstützt, haben Sie keine andere Möglichkeit, als einen Fehlercode zurückzugeben. Ein versagendes C assert()
ergibt sich abort()
angerufen wird, was den Prozess bombardiert. Das ist nicht wirklich vergleichbar mit Standard-Fehlerbehandlung.
Für Gleitkommaoperationen können Sie verwenden NaN
um Fehlerzustände zu signalisieren. Für Integer-Operationen ist ein Fehlercode einfach Ihre einzige Option.
-
Einige Leute (mich eingeschlossen) denken darüber nach
longjmp
könnte verwendet werden, um Ausnahmen für arme Männer in C zu implementieren.– Basile Starynkevitch
13. November 2011 um 19:34 Uhr
-
@BasileStarynkevitch Stimmt, aber wir sprechen von extremer Armut!! 😉
– David Heffernan
13. November 2011 um 19:45 Uhr
Siehe diese Antwort
– brc
13. November 2011 um 19:24 Uhr
Dumm? – Siehe stackoverflow.com/questions/1081409/why-should-i-use-asserts
– Gwyn Evans
13. November 2011 um 19:25 Uhr
assert
s funktionieren nur im Debug-Modus, oder? Sie dienen also nur zum Testen. Ich würde das als Antwort posten, weil ich weiß, dass dies bei C ++ der Fall ist, aber bei C bin ich mir nicht sicher.– Seth Carnegie
13. November 2011 um 19:25 Uhr
Die beiden Links in den obigen Kommentaren beziehen sich auf Fragen, die sich auf C++-Ausnahmen beziehen. Keine Option in C.
– David Heffernan
13. November 2011 um 19:25 Uhr