Ich hatte eine Frage wie diese in einer meiner Prüfungen und bin mir immer noch nicht sicher, wie ich darauf antworten soll. Ich verstehe, dass Behauptungen Möglichkeiten sind, Ihr Programm zu testen, aber ich bin mir nicht sicher, was assert(0)
prüft. Ist das eine Fangfrage? Es wird immer scheitern, aber ich verstehe nicht warum. Was wird überprüft?
Eine Erklärung wäre toll, danke.
Der C++-Standard verschiebt die Definition von assert
nach C-Norm.
C99 §7.2/2:
” Das assert
Makro fügt diagnostische Tests in Programme ein; es erweitert sich zu einem leeren Ausdruck. Wenn es ausgeführt wird, wenn Ausdruck (das einen skalaren Typ haben soll) falsch ist (d. h. gleich 0 vergleicht), schreibt das Assert-Makro Informationen über den bestimmten Aufruf, der fehlgeschlagen ist (einschließlich des Texts des Arguments, des Namens der Quelldatei, der Nummer der Quellzeile). , und der Name der einschließenden Funktion – letztere sind jeweils die Werte der Vorverarbeitungsmakros __FILE__
und __LINE__
und der Kennung __func__
) in der Standardfehlerdatei in einem implementierungsdefinierten Format. Es ruft dann die abort
Funktion.
Im assert(0)
das 0
wird interpretiert als false
also wird diese Behauptung immer scheitern, oder Feuerwenn die Assertionsprüfung aktiviert ist.
Damit behauptet sie das
„Die Hinrichtung wird diesen Punkt niemals erreichen.“
In der Praxis kann es schwierig sein, Compiler zum Schweigen zu bringen, wenn die Ausführung einen bestimmten Punkt erreicht oder nicht erreicht. Oft beschwert sich der Compiler zuerst darüber, dass die Ausführung möglicherweise das Ende einer Funktion erreicht, ohne einen Wert zurückzugeben. Hinzufügen eines assert(0)
Dort sollte das Problem idealerweise gelöst werden, aber dann kann sich der Compiler darüber beschweren assert
oder nicht erkennen, dass Sie bereits wissen, wovor es warnen möchte.
Einer (1)Eine mögliche Maßnahme besteht dann darin, an dieser Stelle auch eine Ausnahme auszulösen:
auto foo( int x )
-> int
{
if( x == 1 ) { return 42; }
assert( 0 ); throw 0; // Should never get here!
}
Natürlich kann dieser Doppelschlag als Makro auf höherer Ebene definiert werden. In Bezug auf den Ausnahmetyp möchten Sie ihn möglicherweise auf not a belassen std::exception
weil dies keine Ausnahme ist, die von einem gewöhnlichen gefangen werden soll catch
irgendwo. Oder, wenn Sie der Standard-Ausnahmehierarchie vertrauen (es ergibt für mich keinen Sinn, aber), können Sie a verwenden std::logic_error
.
Ausschalten assert
Assertion Checking können Sie das Symbol definieren NDEBUG
vor dem Einschließen <assert.h>
.
Dieser Header hat eine spezielle Unterstützung, sodass Sie ihn mehrmals mit oder ohne einfügen können NDEBUG
definiert.
C++11 §17.6.2.2/2:
” Eine Übersetzungseinheit kann Bibliothekskopfzeilen in beliebiger Reihenfolge enthalten (Abschnitt 2). Jedes kann mehr als einmal enthalten sein, ohne dass sich die Wirkung von genau einer Aufnahme unterscheidet, mit der Ausnahme, dass die Auswirkung des Einfügens von einem von beiden ist <cassert>
oder <assert.h>
hängt jeweils von der lexikalisch aktuellen Definition von ab NDEBUG
.
Eine vernünftige Definition des oben diskutierten Doppelschlags kann ebenfalls davon abhängen NDEBUG
ohne Include-Wächter, zB
Datei assert_should_never_get_here.hpp
#include <stdexcept> // std::logic_error
#include <assert.h>
#undef ASSERT_SHOULD_NEVER_GET_HERE
#ifdef NDEBUG
# define ASSERT_SHOULD_NEVER_GET_HERE() \
throw std::logic_error( "Reached a supposed unreachable point" )
#else
# define ASSERT_SHOULD_NEVER_GET_HERE() \
do{ \
assert( "Reached a supposed unreachable point" && 0 ); \
throw 0; \
} while( 0 )
#endif
Haftungsausschluss: Während ich das Anfang der 2000er Jahre mehrmals codiert habe, habe ich den obigen Code nur für diese Antwort erfunden, und obwohl ich ihn mit g ++ getestet habe, ist er möglicherweise nicht unbedingt perfekt.
(1) Siehe die Antwort von Basile Starynkevitch zur Diskussion einer anderen Möglichkeit, der g++-spezifischen Intrinsic __builtin_unreachable
.
Es wird immer scheitern. Das wars so ziemlich. Es wird immer aus demselben Grund fehlschlagen, aus dem “assert(x == 5)” erfolgreich ist, wenn x = 5 ist.
Wenn Sie nach einem fragen Anwendung dann würden Sie es in Codeblöcke stecken, die wirklich nicht passieren sollten.
switch(suit) {
case CLUB:
case DIAMOND:
case HEART:
case SPADE:
// ...
default:
assert(0);
}
Ja, es wird immer scheitern.
assert(0)
oder assert(false)
wird normalerweise zum Markieren verwendet unerreichbarer Codesodass im Debug-Modus eine Diagnosemeldung ausgegeben und das Programm abgebrochen wird, wenn das vermeintlich Unerreichbare tatsächlich erreicht ist, was ein klares Signal dafür ist, dass das Programm nicht das tut, was wir denken.
Im Zusatz zu anderen Antworten (insbesondere dieser), wenn Sie eine aktuelle verwenden GCC (oder Klirren), könnten Sie erwägen, einige zu verwenden GCC eingebautvor allem __builtin_unreachable()
Anstatt von assert(0)
.
Es gibt einige Unterschiede: Erstens assert
kann mit deaktiviert werden -DNDEBUG
. Und __builtin_unreachable
ändert die Art und Weise, wie der Compiler Ihren Code optimiert.
Natürlich wissen einige Compiler nichts davon __builtin_unreachable
.
Und Sie könnten auch erwägen, einige anzurufen [[noreturn]]
C++-Funktion (in C++11 oder besser) – oder __attribute__((noreturn))
zum GCCwie zum Beispiel abort()
Übrigens, assert(0)
ist nicht genau wie das Auslösen einer Ausnahme (da Ausnahmen abgefangen werden können)
Verwenden Sie mehr Ausrufezeichen: assert(!!!”Das, was Sie gehofft haben, würde nicht passieren. Es ist einfach passiert”);
– Hans Passant
12. Dezember 2015 um 7:37 Uhr
Achten Sie nur darauf, eine ungerade Anzahl davon zu verwenden. Und in Anbetracht von Terry Pratchetts beiläufiger Bemerkung: „Mehrere Ausrufezeichen“, fuhr er kopfschüttelnd fort, „sind ein sicheres Zeichen für einen kranken Geist“, und dass 3 Ausrufezeichen sicherlich „mehrere“ sind, ist die einzige Lösung genau 1 .. Jedenfalls erinnere ich mich, dass Andrej Alexandrescu und ich uns nicht auf den besten Weg geeinigt haben. Andrei bevorzugt
assert( "Blah" && condition )
während ich favorisierteassert(("Blah", condition))
(Keiner von uns mochte das Ausrufezeichen). Heute benutze ich&&
weil es einfacher, mehr grokable. Aber deswegen habe ich dann favorisiert(())
…– Prost und hth. – Alf
12. Dezember 2015 um 7:42 Uhr