Suche…


Einführung

Eine Assertion ist ein Prädikat, dass die dargestellte Bedingung in dem Moment wahr sein muss, in dem die Software von der Assertion getroffen wird. Am häufigsten sind einfache Zusicherungen , die zur Ausführungszeit überprüft werden. Statische Zusicherungen werden jedoch zur Kompilierzeit geprüft.

Syntax

  • behaupten (Ausdruck)
  • static_assert (Ausdruck, Nachricht)
  • _Static_assert (Ausdruck, Nachricht)

Parameter

Parameter Einzelheiten
Ausdruck Ausdruck des Skalartyps.
Botschaft String-Literal, das in die Diagnosemeldung aufgenommen werden soll.

Bemerkungen

Sowohl assert und static_assert sind Makros in definierten assert.h .

Die Definition von assert hängt von der Makro NDEBUG , die nicht durch die Standardbibliothek definiert ist. Wenn NDEBUG definiert ist, assert ist ein No-op:

#ifdef NDEBUG
#  define assert(condition) ((void) 0)
#else
#  define assert(condition) /* implementation defined */
#endif

Es gibt unterschiedliche Meinungen darüber, ob NDEBUG immer für Produktionszusammenstellungen verwendet werden sollte.

  • Das Pro-Lager argumentiert , dass assert Anrufe abort und Assertion - Meldungen sind nicht hilfreich für den Endverbraucher, so das Ergebnis Benutzer nicht hilfreich ist. Wenn Sie schwerwiegende Bedingungen zum Einchecken des Produktionscodes haben, sollten Sie normale if/else Bedingungen verwenden und exit oder quick_exit zum quick_exit des Programms verwenden. Im Gegensatz zum abort kann das Programm einige Bereinigungen atexit (über Funktionen, die mit atexit oder at_quick_exit registriert at_quick_exit ).
  • Das Con-Camp argumentiert, dass assert Aufrufe niemals im Produktionscode ausgelöst werden sollten, aber wenn dies der Fall ist, bedeutet dies, dass etwas dramatisch falsch ist und das Programm sich schlechter benimmt, wenn die Ausführung fortgesetzt wird. Daher ist es besser, die Aussagen im Produktionscode zu aktivieren, denn wenn sie feuern, ist die Hölle bereits gebrochen.
  • Eine andere Möglichkeit besteht darin, ein Selbstbrühsystem für Assertions zu verwenden, das die Prüfung immer vornimmt, jedoch Fehler zwischen Entwicklung (wo abort angebracht ist) und Produktion (bei "unerwartetem internem Fehler - wenden Sie sich an den technischen Support" an, möglicherweise angemessener).

static_assert erweitert sich zu _Static_assert , einem Schlüsselwort. Die Bedingung wird zur Kompilierzeit geprüft, daher muss die condition ein konstanter Ausdruck sein. Es ist nicht erforderlich, dass dies in der Entwicklung und in der Produktion anders gehandhabt wird.

Vorbedingung und Nachbedingung

Ein Anwendungsfall für die Behauptung ist Vorbedingung und Nachbedingung. Dies kann sehr nützlich sein, um die Invariante und das vertragliche Design zu erhalten. Für ein Beispiel ist eine Länge immer Null oder positiv, daher muss diese Funktion einen Nullwert oder einen positiven Wert zurückgeben.

#include <stdio.h>
/* Uncomment to disable `assert()` */
/* #define NDEBUG */
#include <assert.h>

int length2 (int *a, int count)
{
    int i, result = 0;

    /* Precondition: */
    /* NULL is an invalid vector */
    assert (a != NULL);
    /* Number of dimensions can not be negative.*/ 
    assert (count >= 0);

    /* Calculation */
    for (i = 0; i < count; ++i) 
    {
        result = result + (a[i] * a[i]);
    }

    /* Postcondition: */
    /* Resulting length can not be negative. */
    assert (result >= 0);
    return result;
}

#define COUNT 3

int main (void)
{
    int a[COUNT] = {1, 2, 3};
    int *b = NULL;
    int r;
    r = length2 (a, COUNT);
    printf ("r = %i\n", r);
    r = length2 (b, COUNT);
    printf ("r = %i\n", r);
    return 0;
}

Einfache Assertion

Eine Assertion ist eine Aussage, mit der behauptet wird, dass eine Tatsache wahr sein muss, wenn diese Codezeile erreicht ist. Zusicherungen sind hilfreich, um sicherzustellen, dass die erwarteten Bedingungen erfüllt werden. Wenn die an eine Assertion übergebene Bedingung wahr ist, gibt es keine Aktion. Das Verhalten bei falschen Bedingungen hängt von Compilerflags ab. Wenn Assertions aktiviert sind, führt eine falsche Eingabe zum sofortigen Programmstopp. Wenn sie deaktiviert sind, wird keine Aktion ausgeführt. Es ist üblich, Assertions in internen Builds und Debug-Builds zu aktivieren und sie in Release-Builds zu deaktivieren, obwohl Assertions häufig in Release aktiviert werden. (Ob die Beendigung besser oder schlechter als Fehler ist, hängt vom Programm ab.) Assertions sollten nur zum Abfangen von internen Programmierfehlern verwendet werden, was normalerweise bedeutet, dass schlechte Parameter übergeben werden.

#include <stdio.h>
/* Uncomment to disable `assert()` */
/* #define NDEBUG */
#include <assert.h>

int main(void)
{
    int x = -1;
    assert(x >= 0);

    printf("x = %d\n", x);   
    return 0;
}

Mögliche Ausgabe mit NDEBUG undefined:

a.out: main.c:9: main: Assertion `x >= 0' failed.

Mögliche Ausgabe mit NDEBUG definiert:

x = -1

Es ist NDEBUG , NDEBUG global zu definieren, sodass Sie Ihren Code mit allen Zusicherungen entweder NDEBUG oder ausschalten können. Eine einfache Möglichkeit, dies zu tun, ist die Definition von NDEBUG als Option für den Compiler oder in einem gemeinsam genutzten Konfigurationsheader (z. B. config.h ).

Statische Assertion

C11

Statische Zusicherungen werden verwendet, um zu überprüfen, ob eine Bedingung erfüllt ist, wenn der Code kompiliert wird. Ist dies nicht der Fall, muss der Compiler eine Fehlermeldung ausgeben und den Kompiliervorgang stoppen.

Eine statische Zusicherung ist eine, die zur Kompilierzeit geprüft wird, nicht zur Laufzeit. Die Bedingung muss ein konstanter Ausdruck sein, und falls false, wird ein Compilerfehler ausgegeben. Das erste Argument, die geprüfte Bedingung, muss ein konstanter Ausdruck sein und das zweite ein Zeichenkettenliteral.

Im Gegensatz zu assert ist _Static_assert ein Schlüsselwort. Ein komfortables Makro static_assert ist in <assert.h> .

#include <assert.h>

enum {N = 5};
_Static_assert(N == 5, "N does not equal 5");
static_assert(N > 10, "N is not greater than 10");  /* compiler error */
C99

Vor C11 gab es keine direkte Unterstützung für statische Assertions. In C99 konnten statische Assertions jedoch mit Makros emuliert werden, die einen Kompilierungsfehler auslösen würden, wenn die Kompilierzeitbedingung falsch war. Im Gegensatz zu _Static_assert muss der zweite Parameter ein geeigneter Token-Name sein, damit ein Variablenname erstellt werden kann. Wenn die Assertion fehlschlägt, wird der Variablenname im Compiler-Fehler angezeigt, da diese Variable in einer syntaktisch falschen Array-Deklaration verwendet wurde.

#define STATIC_MSG(msg, l) STATIC_MSG2(msg, l)
#define STATIC_MSG2(msg,l) on_line_##l##__##msg
#define STATIC_ASSERT(x, msg) extern char STATIC_MSG(msg, __LINE__) [(x)?1:-1]
 
enum { N = 5 };
STATIC_ASSERT(N == 5, N_must_equal_5);
STATIC_ASSERT(N > 5, N_must_be_greater_than_5); /* compile error */

Vor C99 konnten Sie keine Variablen an beliebigen Stellen in einem Block deklarieren. Daher müssen Sie bei der Verwendung dieses Makros äußerst vorsichtig sein und sicherstellen, dass nur dort angezeigt wird, wo eine Variablendeklaration gültig ist.

Geltendmachung eines unerreichbaren Codes

Wenn während der Entwicklung bestimmte Codepfade von der Reichweite des Steuerungsflusses ferngehalten werden müssen, können Sie assert(0) um anzuzeigen, dass eine solche Bedingung fehlerhaft ist:

switch (color) {
    case COLOR_RED:
    case COLOR_GREEN:
    case COLOR_BLUE:
        break;

    default:
        assert(0);
}

Wenn das Argument des assert() -Makros den Wert false ergibt, schreibt das Makro Diagnoseinformationen in den Standardfehlerstrom und bricht das Programm ab. Diese Informationen enthalten die Datei- und Zeilennummer der assert() Anweisung und können beim Debuggen sehr hilfreich sein. Asserts können durch Definieren des Makros NDEBUG .

Eine andere Möglichkeit, ein Programm zu beenden, wenn ein Fehler auftritt, sind die Standardbibliotheksfunktionen exit , quick_exit oder abort . exit und quick_exit nehmen ein Argument an, das an Ihre Umgebung zurückgegeben werden kann. abort() (und damit assert ) kann eine wirklich schwerwiegende Beendigung Ihres Programms sein, und bestimmte Bereinigungen, die andernfalls am Ende der Ausführung durchgeführt würden, werden möglicherweise nicht durchgeführt.

Der Hauptvorteil von assert() ist, dass Debugging-Informationen automatisch gedruckt werden. Das Aufrufen von abort() hat den Vorteil, dass es nicht wie ein Assert deaktiviert werden kann, aber möglicherweise keine Debugging-Informationen angezeigt werden. In einigen Situationen kann die Verwendung beider Konstrukte von Vorteil sein:

if (color == COLOR_RED || color == COLOR_GREEN) {
   ...
} else if (color == COLOR_BLUE) {
   ...
} else {
   assert(0), abort();
}

Wenn Assert assert() aktiviert sind , gibt der assert() Aufruf die Debug-Informationen aus und beendet das Programm. Die Ausführung erreicht niemals den abort() Aufruf. Wenn Asserts deaktiviert sind , macht der assert() Aufruf nichts und abort() wird aufgerufen. Dadurch wird sichergestellt, dass das Programm für diese Fehlerbedingung immer beendet wird. Durch Aktivieren und Deaktivieren wird nur die Auswirkung aktiviert, ob die Debug-Ausgabe gedruckt wird.

Sie sollten eine solche assert niemals im Produktionscode belassen, da die Debug-Informationen für Endbenutzer nicht hilfreich sind und der abort im Allgemeinen eine viel zu schwerwiegende Beendigung darstellt, die die für exit oder quick_exit installierten Cleanup-Handler quick_exit .

Bestätigen Sie Fehlermeldungen

Es gibt einen Trick, der neben einer Assertion eine Fehlermeldung anzeigen kann. Normalerweise würden Sie Code so schreiben

void f(void *p)
{
    assert(p != NULL);
    /* more code */
}

Wenn die Zusicherung fehlgeschlagen ist, würde eine Fehlermeldung ähneln

Assertion fehlgeschlagen: p! = NULL, Datei main.c, Zeile 5

Sie können jedoch auch das logische AND ( && ) verwenden, um eine Fehlermeldung zu geben

void f(void *p)
{
    assert(p != NULL && "function f: p cannot be NULL");
    /* more code */
}

Wenn die Zusicherung fehlschlägt, wird eine Fehlermeldung in etwa folgendermaßen angezeigt

Assertion fehlgeschlagen: p! = NULL && "Funktion f: p kann nicht NULL sein", Datei main.c, Zeile 5

Der Grund, warum dies funktioniert, ist, dass ein Zeichenfolgenliteral immer den Wert ungleich Null (wahr) ergibt. Das Hinzufügen von && 1 zu einem booleschen Ausdruck hat keine Auswirkung. Das Hinzufügen von && "error message" hat also keine Auswirkung, außer dass der Compiler den gesamten fehlgeschlagenen Ausdruck anzeigt.



Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow