Wann sollten wir Asserts in C verwenden?

Lesezeit: 5 Minuten

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.

  • 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

  • asserts 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

Benutzeravatar von Fred Foo
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 assertaber es ist als temporäres Debugging-Tool nützlich.

Benutzeravatar von Kerrek SB
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.)

Benutzeravatar von Basile Starynkevitch
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.

Benutzeravatar von David Heffernan
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

1388330cookie-checkWann sollten wir Asserts in C verwenden?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy