Was ist die "Assert" -Funktion?


261

Ich habe OpenCV-Tutorials studiert und bin auf die assertFunktion gestoßen. was tut es?


20
Beachten Sie den Hinweis von man assert: "assert () ist als Makro implementiert. Wenn der getestete Ausdruck Nebenwirkungen hat, hängt das Programmverhalten davon ab, ob NDEBUG definiert ist. Dies kann zu Heisenbugs führen, die beim Aktivieren des Debuggens verschwinden . "
Johannes Schaub - litb


35
@ S.Lott Jetzt finden Leute, die Google suchen, diese Seite als eines der Top-Suchergebnisse. Sie bieten eine gute Peer-Review-Antwort auf ihre Frage und fördern gleichzeitig den Stapelüberlauf. Es ist also eine +1 von mir!
Matt Grum

6
Es ist ein -1 von mir. Das Top-Suchergebnis sollte die Dokumentation sein , die das OP eigentlich hätte konsultieren müssen.
Leichtigkeitsrennen im Orbit

9
@ LightnessRacesinOrbit. Nennen Sie mich faul, aber ich bevorzuge es, die hervorragenden komprimierten, zusammengefassten und erklärten Lesarten der Dokumentation zu verwenden, die sachkundige SO-Benutzer wie Sie bereitstellen. Mein herzlicher Dank :)
Tyson Hilmer

Antworten:


297

assertbeendet das Programm (normalerweise mit einer Nachricht, die die assert-Anweisung zitiert), wenn sich herausstellt, dass das Argument falsch ist. Es wird häufig beim Debuggen verwendet, um das Programm offensichtlicher zum Scheitern zu bringen, wenn ein unerwarteter Zustand auftritt.

Beispielsweise:

assert(length >= 0);  // die if length is negative.

Sie können auch eine informativere Nachricht hinzufügen, die angezeigt wird, wenn dies wie folgt fehlschlägt:

assert(length >= 0 && "Whoops, length can't possibly be negative! (didn't we just check 10 lines ago?) Tell jsmith");

Oder so:

assert(("Length can't possibly be negative! Tell jsmith", length >= 0));

Wenn Sie einen Release-Build (ohne Debug) erstellen, können Sie auch den Aufwand für die Auswertung von assertAnweisungen NDEBUGverringern, indem Sie das Makro definieren , normalerweise mit einem Compiler-Switch. Die Folge davon ist, dass sich Ihr Programm niemals auf das ausgeführte Assert-Makro verlassen sollte .

// BAD
assert(x++);

// GOOD
assert(x);    
x++;

// Watch out! Depends on the function:
assert(foo());

// Here's a safer way:
int ret = foo();
assert(ret);

Aus der Kombination des Programms, das abort () aufruft und nicht garantiert wird, dass etwas getan wird, sollten Asserts nur verwendet werden, um Dinge zu testen, die der Entwickler angenommen hat, anstatt beispielsweise, dass der Benutzer eine Zahl anstelle eines Buchstabens eingibt (was sein sollte) auf andere Weise gehandhabt werden).


49
" assertlöst normalerweise eine Ausnahme aus" - in C ++ wird keine "Ausnahme" ausgelöst, die als Abbruch bezeichnet wird ... es ist ein bisschen anders.
Artyom

5
Ich glaube nicht, dass diese Antwort ungefähr die gleichen Sprachen hat wie die Frage (C und C ++). In C und C ++ löst assert keine Ausnahme aus, das Argument steht in Klammern und das #Zeichen führt keinen Kommentar ein.
Steve Jessop

Hier sind Ihre Optionen: Erstellen Sie das Antwort-Community-Wiki und bearbeiten Sie Ihre Frage, indem Sie das alte Material entfernen und andere bitten, die richtigen Informationen zu platzieren. Auf diese Weise wirken sich Abstimmungen nicht auf Ihren Repräsentanten aus, und die Antwort kann verbessert werden.
Johannes Schaub - litb

2
Länge> = 0 wird auch falsch sein, wenn Länge NaN ist
Andreas

1
Derzeit funktioniert in VS 2015 die Bestätigung mit einer Fehlermeldung nicht, da sie nicht in Ordnung ist. Es sollte seinassert("error message", expression)
Dooskington

102

Die assert Computer - Anweisung ist auf die Aussage analog stellen Sie sicher , auf Englisch.


131
Nicht ganz. "Stellen Sie sicher, dass das Licht ausgeschaltet ist" bedeutet "Überprüfen Sie das Licht und schalten Sie es aus, wenn es eingeschaltet ist", nicht "Überprüfen Sie, ob das Licht ausgeschaltet ist, und wenn nicht, explodieren Sie bitte." Ich würde sagen, "Double-Check" ist eine genauere Übersetzung.
Luke Maurer

7
@ Luke, das zeigt die Wunder der englischen Sprache, indem die Sprache viele Möglichkeiten bietet, dasselbe zu sagen. Betrachten Sie jedoch assert (Länge> 0). Wir können das also so übersetzen, dass "die Länge größer als Null ist" oder "sichergestellt wird, dass die Länge größer als Null ist" . Obwohl beide Optionen eindeutig funktionieren, bevorzuge ich meine;)
Blake7

4
Nun, aber die andere Interpretation lautet: " Lass die Länge größer als Null sein." Es gibt also etwas mehr Mehrdeutigkeit.
Luke Maurer

29
Es ist enger analog zum englischen Verb "assert"
Steve Carter

In der Tat könnte "sicherstellen" als "überprüfen und wenn nicht in Ordnung, ändern" interpretiert werden.
Erik Bongers

14

Schau es dir an

assert () Beispielprogramm in C ++

Viele Compiler bieten ein assert () -Makro an. Das assert () -Makro gibt TRUE zurück, wenn sein Parameter TRUE auswertet, und führt eine Aktion aus, wenn es FALSE auswertet. Viele Compiler brechen das Programm mit einer Assert () ab, die fehlschlägt. andere werden eine Ausnahme auslösen

Eine leistungsstarke Funktion des assert () -Makros besteht darin, dass der Präprozessor es in keinen Code reduziert, wenn DEBUG nicht definiert ist. Es ist eine große Hilfe während der Entwicklung, und wenn das Endprodukt ausgeliefert wird, gibt es keine Leistungseinbußen oder eine Vergrößerung der ausführbaren Version des Programms.

Z.B

#include <stdio.h>
#include <assert.h>

void analyze (char *, int);

int main(void)
{
   char *string = "ABC";
   int length = 3;

   analyze(string, length);
   printf("The string %s is not null or empty, "
          "and has length %d \n", string, length);
}

void analyze(char *string, int length)
{
   assert(string != NULL);     /* cannot be NULL */
   assert(*string != '\0');    /* cannot be empty */
   assert(length > 0);         /* must be positive */
}

/****************  Output should be similar to  ******************
The string ABC is not null or empty, and has length 3

11
Sollte nicht "wenn NDEBUG definiert ist" sein?
RichN

2
Worum geht es bei diesen "vielen Compilern"? MSVC und GCC sind beide Standards, die diesem entsprechen. Welche nicht konformen Compiler: haben keine Behauptung; Drucken Sie keine Nachricht und brechen Sie den Vorgang ab, wenn eine Bestätigung fehlschlägt. DEBUG anstelle des richtigen NDEBUG verwenden?
Steve Jessop

lmao, natürlich ist es eine website namens java-samples , die das so falsch macht.
underscore_d

6

Die Funktion assert () kann Programmfehler diagnostizieren. In C ist es definiert in <assert.h>und in C ++ ist es definiert in <cassert>. Sein Prototyp ist

void assert(int expression);

Der Argumentausdruck kann alles sein, was Sie testen möchten - eine Variable oder ein beliebiger C-Ausdruck. Wenn der Ausdruck TRUE ergibt, führt assert () nichts aus. Wenn der Ausdruck FALSE ergibt, zeigt assert () eine Fehlermeldung auf stderr an und bricht die Programmausführung ab.

Wie benutzt man assert ()? Es wird am häufigsten verwendet, um Programmfehler aufzuspüren (die sich von Kompilierungsfehlern unterscheiden). Ein Fehler verhindert nicht das Kompilieren eines Programms, führt jedoch dazu, dass es falsche Ergebnisse liefert oder nicht ordnungsgemäß ausgeführt wird (z. B. Sperren). Beispielsweise kann ein Finanzanalyseprogramm, das Sie schreiben, gelegentlich falsche Antworten geben. Sie vermuten, dass das Problem dadurch verursacht wird, dass die Variable Zinssatz einen negativen Wert annimmt, was niemals passieren sollte. Um dies zu überprüfen, platzieren Sie die Anweisung

assert (Zinssatz> = 0); an Stellen im Programm, an denen Zinssatz verwendet wird. Sollte die Variable jemals negativ werden, werden Sie vom Makro assert () benachrichtigt. Anschließend können Sie den entsprechenden Code untersuchen, um die Ursache des Problems zu ermitteln.

Führen Sie das folgende Beispielprogramm aus, um zu sehen, wie assert () funktioniert . Wenn Sie einen Wert ungleich Null eingeben, zeigt das Programm den Wert an und wird normal beendet. Wenn Sie Null eingeben, erzwingt das assert () -Makro eine abnormale Programmbeendigung. Die genaue Fehlermeldung hängt von Ihrem Compiler ab. Hier ein typisches Beispiel:

Assertion fehlgeschlagen: x, Datei list19_3.c, Zeile 13 Beachten Sie, dass Ihr Programm im Debug-Modus kompiliert werden muss, damit assert () funktioniert. Informationen zum Aktivieren des Debug-Modus finden Sie in der Compiler-Dokumentation (wie in Kürze erläutert). Wenn Sie die endgültige Version später im Release-Modus kompilieren, werden die assert () -Makros deaktiviert.

 int x;

 printf("\nEnter an integer value: ");
 scanf("%d", &x);

 assert(x >= 0);

 printf("You entered %d.\n", x);
 return(0);

Geben Sie einen ganzzahligen Wert ein: 10

Sie haben 10 eingegeben.

Geben Sie einen ganzzahligen Wert ein: -1

Fehlermeldung: Abnormale Programmbeendigung

Ihre Fehlermeldung kann je nach System und Compiler unterschiedlich sein, aber die allgemeine Idee ist dieselbe.


Sie haben erklärt, wie Ihr Beispielprogramm mit assert funktioniert. Nicht wie sich behaupten funktioniert. Wie beendet es das Programm abnormal? wirft es eine Art Ausnahme? Welche Art? Erzeugt es ein spezielles Signal? Welches Signal? Können Behauptungen durch irgendeine Art von C ++ - Try-Catch-Mechanismus "abgefangen" werden?
Motti Shneor

4

Dinge wie "löst eine Ausnahme aus" und "stoppt die Ausführung" gelten möglicherweise für die meisten Compiler, aber nicht für alle. (Übrigens, gibt es Aussagen, die wirklich Ausnahmen auslösen?)

Hier ist eine interessante, etwas andere Bedeutung von assert, die von c6x und anderen TI-Compilern verwendet wird: Wenn bestimmte Assert-Anweisungen angezeigt werden, verwenden diese Compiler die Informationen in dieser Anweisung, um bestimmte Optimierungen durchzuführen. Böse.

Beispiel in C:

int dot_product(short *x, short *y, short z)
{
  int sum = 0
  int i;

  assert( ( (int)(x) & 0x3 ) == 0 );
  assert( ( (int)(y) & 0x3 ) == 0 );

  for( i = 0 ; i < z ; ++i )
    sum += x[ i ] * y[ i ];
  return sum;
}

Dies teilt dem Compiler mit, dass die Arrays an 32-Bit-Grenzen ausgerichtet sind, sodass der Compiler spezifische Anweisungen für diese Art der Ausrichtung generieren kann.


1
Was tun sie also, wenn die Behauptung falsch ist und NDEBUG nicht gesetzt ist? Wenn dies die Version von assert aus <assert.h> ist, muss der Standard eine Nachricht drucken und abbrechen. Offensichtlich sagt der Standard nicht, dass sie nicht basierend auf der Wahrheit der Aussage optimieren dürfen, aber um konform zu sein, müssen sie immer noch abbrechen, wenn es falsch ist.
Steve Jessop

1
Sie folgen dem Standardverhalten
am

1

C ++ 11 N3337 Standardentwurf

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf

19.3 Behauptungen

1 Der in (Tabelle 42) beschriebene Header <cassert> enthält ein Makro zum Dokumentieren von C ++ - Programmzusicherungen und einen Mechanismus zum Deaktivieren der Bestätigungsprüfungen.

2 Der Inhalt entspricht dem Standard-C-Bibliotheksheader <assert.h>.

C99 N1256 Standardentwurf

http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1256.pdf

7.2 Diagnose <assert.h>

1 Der Header <assert.h>definiert das Assert-Makro und verweist auf ein anderes Makro, NDEBUGdas nicht durch definiert ist <assert.h>. Wenn NDEBUGan der Stelle in der Quelldatei, an der <assert.h> enthalten ist, ein Makroname definiert ist, wird das assert-Makro einfach als definiert

 #define assert(ignore) ((void)0)

Das Assert-Makro wird jedes Mal, wenn <assert.h>es enthalten ist, entsprechend dem aktuellen Status von NDEBUG neu definiert .

2. Das Assert-Makro wird als Makro und nicht als tatsächliche Funktion implementiert. Wenn die Makrodefinition unterdrückt wird, um auf eine tatsächliche Funktion zuzugreifen, ist das Verhalten undefiniert.

7.2.1 Programmdiagnose

7.2.1.1 Das Assert-Makro

Zusammenfassung

1.

#include <assert.h>
void assert(scalar expression);

Beschreibung

2 Das Assert-Makro fügt Diagnosetests in Programme ein. es erweitert sich zu einem leeren Ausdruck. Wenn es ausgeführt wird und der Ausdruck (der einen Skalartyp haben soll) falsch ist (dh gleich 0 ist), schreibt das Assert-Makro Informationen über den bestimmten Aufruf, der fehlgeschlagen ist (einschließlich des Textes des Arguments, des Namens des Quelldatei, Quellzeilennummer und Name der umschließenden Funktion (letztere sind jeweils die Werte der Vorverarbeitungsmakros __FILE__und __LINE__und des Bezeichners __func__) im Standardfehlerstrom in einem implementierungsdefinierten Format. 165) Es ruft dann die Abbruchfunktion auf.

Kehrt zurück

3 Das Assert-Makro gibt keinen Wert zurück.


1

Es gibt drei Hauptgründe für die Verwendung der Funktion assert () gegenüber der normalen Funktion if else und printf

  1. Die Funktion assert () wird hauptsächlich in der Debugging-Phase verwendet. Es ist mühsam, jedes Mal, wenn Sie eine Bedingung testen möchten, die möglicherweise nicht einmal im endgültigen Code enthalten ist, eine printf-Anweisung zu schreiben.

  2. In großen Softwarebereitstellungen ist assert sehr praktisch, wenn Sie den Compiler veranlassen können, die assert-Anweisungen mithilfe des definierten NDEBUG-Makros zu ignorieren, bevor Sie die Header-Datei für die assert () -Funktion verknüpfen.

  3. assert () ist praktisch, wenn Sie eine Funktion oder einen Code entwerfen und eine Vorstellung davon bekommen möchten, welche Grenzen der Code hat und nicht funktioniert, und schließlich ein if else für die Bewertung einschließen, das im Wesentlichen mit Annahmen spielt.


0

Diese Funktion stoppt die Programmausführung, wenn der ausgewertete Wert false ist. Normalerweise ist es von einem Makro umgeben, sodass es beim Kompilieren mit Release-Einstellungen nicht in die resultierende Binärdatei kompiliert wird.

Es dient zum Testen der von Ihnen getroffenen Annahmen. Beispielsweise:

void strcpy(char* dest, char* src){
    //pointers shouldn't be null
    assert(dest!=null);
    assert(src!=null);

    //copy string
    while(*dest++ = *src++);
}

Das Ideal, das Sie möchten, ist, dass Sie einen Fehler in Ihrem Programm machen können, z. B. das Aufrufen einer Funktion mit ungültigen Argumenten, und Sie eine Bestätigung treffen, bevor sie fehlerhaft wird (oder nicht wie erwartet funktioniert).


Warum verwenden wir nicht einfach if & else & fügen einige Protokollierungsinformationen hinzu?
Asad Khan

1
Weil Sie niemals einen Nullzeiger an strcpy übergeben sollten. Es ist eines dieser Dinge, die nicht passieren sollten. Wenn ein Nullzeiger übergeben wurde, zeigt dies an, dass etwas auf einer höheren Ebene durcheinander geraten ist. Bestenfalls müssen Sie das Programm aufgrund unerwarteter Datenwerte (entweder dest ist falsch oder null) weiter vom Problem entfernt abstürzen.
Yacoby

-5

Darüber hinaus können Sie damit überprüfen, ob die dynamische Zuordnung erfolgreich war.

Codebeispiel:

int ** p;
p = new int * [5];      // Dynamic array (size 5) of pointers to int
for (int i = 0; i < 5; ++i) {
    p[i] = new int[3]; // Each i(ptr) is now pointing to a dynamic
                       // array (size 3) of actual int values
}

assert (p);            // Check the dynamic allocation.

Ähnlich zu:

if (p == NULL) {
    cout << "dynamic allocation failed" << endl;
    exit(1);
}

3
Nein, newlöst eine Ausnahme bei Zuordnungsfehlern aus, es sei denn, Sie geben an nothrow(was Sie hier nicht getan haben). Darüber hinaus ist Ihre Formatierung seltsam und exitböse.
Leichtigkeitsrennen im Orbit

Ja, du hast recht. Ich habe vergessen, nicht hinzuzufügen. Würde gerne sehen, wie Sie anstelle von Exit verwenden werden
Sadikov

1
@Sadikov Jeder andere würde eine solche Fehlerbedingung mit Code behandeln, der beim Erstellen im Release-Modus nicht vollständig entfernt wird. Dadurch bleiben Ihre Benutzer ohne Schutz und sind undefiniertem Verhalten ausgeliefert, wenn eine Vorbedingung nicht erfüllt ist und dies dank dessen ist nie überprüft und gefangen . assert()dient nur zum Debuggen und Auslöschen von Dingen, die niemals, niemals, niemals passieren sollten - lange bevor ein Release-Build erstellt wird.
underscore_d
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.