Zoeken…


Invoering

Een bewering is een predicaat dat de gepresenteerde toestand waar moet zijn op het moment dat de bewering door de software wordt aangetroffen. De meest voorkomende zijn eenvoudige beweringen , die worden gevalideerd tijdens de uitvoering. Statische beweringen worden echter tijdens het compileren gecontroleerd.

Syntaxis

  • assert (expressie)
  • static_assert (expressie, bericht)
  • _Static_assert (expressie, bericht)

parameters

Parameter Details
uitdrukking expressie van scalair type.
bericht letterlijke tekenreeks die moet worden opgenomen in het diagnostische bericht.

Opmerkingen

Zowel assert als static_assert zijn macro's gedefinieerd in assert.h .

De definitie van assert hangt af van de macro NDEBUG die niet wordt gedefinieerd door de standaardbibliotheek. Als NDEBUG is gedefinieerd, is assert een no-op:

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

De meningen lopen uiteen of NDEBUG altijd moet worden gebruikt voor productiecompilaties.

  • De pro-camp beweert dat assert abort en bewaarberichten niet nuttig zijn voor eindgebruikers, dus het resultaat is niet nuttig voor de gebruiker. Als u fatale voorwaarden heeft om de productiecode in te checken, moet u normale if/else voorwaarden gebruiken en exit of quick_exit om het programma te beëindigen. In tegenstelling tot abort , stellen deze programma's het programma in staat enige opruimingen te doen (via functies die zijn geregistreerd bij atexit of at_quick_exit ).
  • Het kamp beweert dat assert nooit in productiecode mogen afvuren, maar als ze dat doen, betekent de aangevinkte voorwaarde dat er iets dramatisch mis is en het programma zich slechter zal gedragen als de uitvoering doorgaat. Daarom is het beter om de beweringen actief te hebben in de productiecode, want als ze schieten, is de hel al losgebroken.
  • Een andere optie is om een huisbrouwsysteem van beweringen te gebruiken dat altijd de controle uitvoert, maar fouten anders behandelt tussen ontwikkeling (waar abort geschikt is) en productie (waar een 'onverwachte interne fout - neem contact op met Technische Ondersteuning').

static_assert breidt uit naar _Static_assert wat een trefwoord is. De aandoening wordt gecontroleerd tijdens het compileren, waardoor condition moet een constante expressie. Het is niet nodig dat dit anders wordt behandeld tussen ontwikkeling en productie.

Voorwaarde en postconditie

Eén use case voor bewering is voorwaarde en postconditie. Dit kan zeer nuttig zijn om invariant en ontwerp per contract te onderhouden. Voor een voorbeeld is een lengte altijd nul of positief, dus deze functie moet een nul of positieve waarde retourneren.

#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;
}

Eenvoudige bewering

Een bewering is een bewering die wordt gebruikt om te beweren dat een feit waar moet zijn wanneer die regel code wordt bereikt. Beweringen zijn nuttig om ervoor te zorgen dat aan de verwachte voorwaarden wordt voldaan. Wanneer de voorwaarde die aan een bewering wordt doorgegeven, waar is, is er geen actie. Het gedrag onder valse omstandigheden is afhankelijk van compilervlaggen. Wanneer beweringen zijn ingeschakeld, zorgt een valse invoer ervoor dat het programma onmiddellijk wordt gestopt. Als ze zijn uitgeschakeld, wordt er geen actie ondernomen. Het is gebruikelijk om beweringen in interne en debug-builds in te schakelen en uit te schakelen in release-builds, hoewel beweringen vaak zijn ingeschakeld in release. (Of beëindiging beter of slechter is dan fouten, is afhankelijk van het programma.) Beweringen mogen alleen worden gebruikt om interne programmeerfouten op te vangen, wat meestal betekent dat er slechte parameters worden doorgegeven.

#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;
}

Mogelijke uitvoer met NDEBUG niet gedefinieerd:

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

Mogelijke uitvoer met NDEBUG :

x = -1

Het is een goede gewoonte om NDEBUG globaal te definiëren, zodat u uw code eenvoudig kunt compileren met alle beweringen aan of uit. Een eenvoudige manier om dit te doen, is NDEBUG definiëren als een optie voor de compiler, of definiëren in een gedeelde configuratiekop (bijv. config.h ).

Statische bewering

C11

Statische beweringen worden gebruikt om te controleren of een voorwaarde waar is wanneer de code wordt gecompileerd. Als dit niet het geval is, moet de compiler een foutmelding geven en het compilatieproces stoppen.

Een statische bewering is er een die tijdens het compileren wordt gecontroleerd, niet tijdens de uitvoering. De voorwaarde moet een constante expressie zijn en als false resulteert in een compilerfout. Het eerste argument, de voorwaarde die is aangevinkt, moet een constante uitdrukking zijn en het tweede een letterlijke tekenreeks.

In tegenstelling tot assert is _Static_assert een trefwoord. Een gemakkelijke macro static_assert is gedefinieerd 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

Vóór C11 was er geen directe ondersteuning voor statische beweringen. In C99 kunnen statische beweringen echter worden geëmuleerd met macro's die een compilatiefout zouden veroorzaken als de compilatietijd niet waar was. In tegenstelling tot _Static_assert moet de tweede parameter een juiste _Static_assert , zodat hiermee een variabelenaam kan worden gemaakt. Als de bewering mislukt, wordt de variabelenaam weergegeven in de compilerfout, omdat die variabele is gebruikt in een syntactisch onjuiste arraydeclaratie.

#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 */

Vóór C99 kon je geen variabelen op willekeurige locaties in een blok declareren, dus je zou uiterst voorzichtig moeten zijn met het gebruik van deze macro, ervoor zorgen dat het alleen verschijnt waar een variabeledeclaratie geldig zou zijn.

Bewering van onbereikbare code

Wanneer tijdens de ontwikkeling bepaalde codepads buiten het bereik van de besturingsstroom moeten worden voorkomen, kunt u assert(0) om aan te geven dat een dergelijke voorwaarde onjuist is:

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

    default:
        assert(0);
}

Wanneer het argument van de macro assert() false evalueert, schrijft de macro diagnostische informatie naar de standaardfoutstroom en wordt het programma afgebroken. Deze informatie bevat het bestand en het regelnummer van de assert() -instructie en kan zeer nuttig zijn bij het opsporen van fouten. Beweringen kunnen worden uitgeschakeld door de macro NDEBUG definiëren.

Een andere manier om een programma te beëindigen wanneer er een fout optreedt, is met de standaardbibliotheekfuncties exit , quick_exit of abort . exit en quick_exit nemen een argument dat aan uw omgeving kan worden doorgegeven. abort() (en dus assert ) kan een echt ernstige beëindiging van uw programma zijn, en bepaalde opruimingen die anders aan het einde van de uitvoering zouden worden uitgevoerd, worden mogelijk niet uitgevoerd.

Het primaire voordeel van assert() is dat het automatisch foutopsporingsinformatie afdrukt. Het aanroepen van abort() heeft het voordeel dat het niet als een assert kan worden uitgeschakeld, maar het mag er niet voor zorgen dat foutopsporingsinformatie wordt weergegeven. In sommige situaties kan het nuttig zijn om beide constructies samen te gebruiken:

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

Wanneer asserts zijn ingeschakeld , drukt de assert() -oproep foutopsporingsinformatie af en wordt het programma beëindigd. Uitvoering bereikt nooit de aanroep abort() . Wanneer asserts zijn uitgeschakeld , doet de call assert() niets en wordt abort() aangeroepen. Dit zorgt ervoor dat het programma altijd eindigt voor deze foutconditie; inschakelen en uitschakelen beweert alleen effecten of de foutopsporingsuitvoer al dan niet wordt afgedrukt.

U mag nooit een dergelijke assert achterlaten in de productiecode, omdat de foutopsporingsinformatie niet nuttig is voor eindgebruikers en omdat abort over het algemeen een veel te ernstige beëindiging is die quick_exit verhindert die zijn geïnstalleerd voor exit of quick_exit om te worden uitgevoerd.

Bevestig foutmeldingen

Er is een truc die een foutmelding samen met een bewering kan weergeven. Normaal zou u code zoals deze schrijven

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

Als de bewering mislukte, zou een foutmelding lijken

Bewering mislukt: p! = NULL, bestand main.c, regel 5

U kunt echter ook logische EN ( && ) gebruiken om een foutmelding te geven

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

Als de bewering niet slaagt, zal een foutmelding zoiets als dit lezen

Bewering mislukt: p! = NULL && "functie f: p kan niet NULL zijn", bestand main.c, regel 5

De reden waarom dit werkt, is dat een letterlijke tekenreeks altijd evalueert naar niet-nul (waar). Het toevoegen van && 1 aan een Booleaanse uitdrukking heeft geen effect. Het toevoegen van && "error message" heeft dus ook geen effect, behalve dat de compiler de volledige expressie zal weergeven die is mislukt.



Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow