Cos'è la funzione "assert"?


262

Ho studiato tutorial di OpenCV e mi sono imbattuto nella assertfunzione; Che cosa fa?


20
Nota la nota di man assert: "assert () è implementato come una macro; se l'espressione testata ha effetti collaterali, il comportamento del programma sarà diverso a seconda che sia definito NDEBUG. Ciò potrebbe creare Heisenbugs che scompaiono quando il debug è attivo ".
Johannes Schaub - litb


35
@ S. Lott ora le persone che cercano su Google troveranno questa pagina come uno dei migliori risultati di ricerca, fornendo una buona risposta peer review alla loro domanda e promuovendo Stack Overflow allo stesso tempo, quindi è un +1 da parte mia!
Matt Grum,

6
È un -1 da parte mia. Il risultato di ricerca principale dovrebbe essere la documentazione che l'OP avrebbe dovuto consultare in primo luogo.
Razze di leggerezza in orbita

9
@LightnessRacesinOrbit. Chiamami pigro, ma preferisco usare le eccellenti letture condensate, riassunte e spiegate della documentazione fornite da utenti SO esperti come te. Grazie di cuore :)
Tyson Hilmer,

Risposte:


298

asserttermina il programma (di solito con un messaggio che cita la dichiarazione di asserzione) se il suo argomento risulta falso. È comunemente usato durante il debug per rendere più evidente il fallimento del programma se si verifica una condizione imprevista.

Per esempio:

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

Puoi anche aggiungere un messaggio più informativo da visualizzare in caso di errore:

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

Oppure così:

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

Quando si esegue una build di rilascio (non di debug), è anche possibile rimuovere l'overhead delle assertistruzioni di valutazione definendo la NDEBUGmacro, in genere con uno switch del compilatore. Il corollario di questo è che il tuo programma non dovrebbe mai fare affidamento sulla macro assert in esecuzione.

// 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);

Dalla combinazione del programma che chiama abort () e che non si garantisce che faccia nulla, le asserzioni dovrebbero essere usate solo per testare cose che lo sviluppatore ha assunto piuttosto che, ad esempio, l'utente inserendo un numero anziché una lettera (che dovrebbe essere gestito con altri mezzi).


49
" assertSolitamente solleva un'eccezione" - in C ++ non genera "eccezione", chiama abort ... è un po 'diverso.
Artyom,

5
Non credo che questa risposta riguardi le stesse lingue in cui la domanda è taggata (C e C ++). In C e C ++, asserire non solleva un'eccezione, ha parentesi attorno al suo argomento e il #personaggio non introduce un commento.
Steve Jessop,

Ecco le tue opzioni: fai la risposta wiki-community e modifica la tua domanda rimuovendo le vecchie cose, chiedendo ad altri di inserire le informazioni corrette. In questo modo, i voti negativi non influiranno sul tuo rappresentante e le persone possono migliorare la risposta.
Johannes Schaub - litb

2
length> = 0 risulterà falso anche se la lunghezza è NaN
Andreas

1
Attualmente, in VS 2015, l'asserzione con un messaggio di errore non funzionerà perché non funziona. Dovrebbe essereassert("error message", expression)
Dooskington,

102

L' affermazione del computer assert è analoga all'affermazione assicurarsi in inglese.


131
Bene, non proprio. "Assicurati che la luce sia spenta" significa "controlla la luce e spegnila se è accesa", non "vedi se la luce è spenta e se non esploda, per favore." Direi che "doppio controllo" è una traduzione più ravvicinata.
Luke Maurer,

7
@Luke, che illustra le meraviglie della lingua inglese, in quanto la lingua offre molti modi per dire la stessa cosa. Ma considera assert (lunghezza> 0). Quindi possiamo tradurre che "ricontrollare che la lunghezza sia maggiore di zero" o "assicurarsi che la lunghezza sia maggiore di zero" . Mentre chiaramente entrambe le opzioni funzionano, preferisco ancora la mia;)
Blake7

4
Bene, ma l'altra interpretazione è " fai in modo che la lunghezza sia maggiore di zero". Quindi c'è un po 'più di ambiguità.
Luke Maurer

29
È più analogo al verbo inglese "assert"
Steve Carter

In effetti, "assicurati" potrebbe essere interpretato come "controlla, e se non va bene, cambia".
Erik Bongers,

14

Date un'occhiata al

programma di esempio assert () in C ++

Molti compilatori offrono una macro assert (). La macro assert () restituisce VERO se il suo parametro valuta VERO e intraprende un qualche tipo di azione se valuta FALSO. Molti compilatori interromperanno il programma su un assert () che fallisce; altri genereranno un'eccezione

Una potente funzionalità della macro assert () è che il preprocessore non lo comprime in alcun codice se DEBUG non è definito. È di grande aiuto durante lo sviluppo e quando il prodotto finale viene spedito non ci sono penalità di prestazione né aumento delle dimensioni della versione eseguibile del programma.

Per esempio

#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
Non dovrebbe essere "se NDEBUG è definito"?
RichN,

2
Di cosa parlano questi "molti compilatori"? MSVC e GCC sono entrambi standard conformi a questo. Quali compilatori non conformi: non hanno asserire; non stampare un messaggio e interrompere quando un'asserzione fallisce; usare DEBUG invece del corretto NDEBUG?
Steve Jessop,

Lmao, ovviamente è un sito web chiamato java-samples che sbaglia così tanto.
underscore_d

6

La funzione assert () può diagnosticare i bug del programma. In C, è definito in <assert.h>, e in C ++ è definito in <cassert>. Il suo prototipo è

void assert(int expression);

L'espressione argomento può essere qualsiasi cosa tu voglia testare - una variabile o qualsiasi espressione C. Se l'espressione restituisce VERO, assert () non fa nulla. Se expression restituisce FALSE, assert () visualizza un messaggio di errore su stderr e interrompe l'esecuzione del programma.

Come usi assert ()? Viene utilizzato più frequentemente per rintracciare i bug del programma (che sono distinti dagli errori di compilazione). Un bug non impedisce la compilazione di un programma, ma provoca risultati errati o l'esecuzione non corretta (blocco, ad esempio). Ad esempio, un programma di analisi finanziaria che stai scrivendo potrebbe occasionalmente dare risposte errate. Sospetti che il problema sia causato dalla variabile interest_rate che assume un valore negativo, cosa che non dovrebbe mai accadere. Per verificare ciò, inserire la dichiarazione

assert (tasso_interesse> = 0); nelle posizioni del programma in cui viene utilizzato interest_rate. Se la variabile diventa negativa, la macro assert () ti avvisa. È quindi possibile esaminare il codice pertinente per individuare la causa del problema.

Per vedere come funziona assert (), esegui il seguente programma di esempio . Se si immette un valore diverso da zero, il programma visualizza il valore e termina normalmente. Se si inserisce zero, la macro assert () forza la chiusura anomala del programma. Il messaggio di errore esatto che vedi dipenderà dal tuo compilatore, ma ecco un esempio tipico:

Asserzione non riuscita: x, elenco file19_3.c, riga 13 Si noti che, affinché assert () funzioni, il programma deve essere compilato in modalità debug. Fare riferimento alla documentazione del compilatore per informazioni sull'abilitazione della modalità debug (come spiegato in un momento). Quando successivamente compilerai la versione finale in modalità di rilascio, le macro assert () sono disabilitate.

 int x;

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

 assert(x >= 0);

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

Immettere un valore intero: 10

Hai inserito 10.

Immettere un valore intero: -1

Messaggio di errore: chiusura anomala del programma

Il messaggio di errore potrebbe essere diverso, a seconda del sistema e del compilatore, ma l'idea generale è la stessa.


Hai spiegato come funziona il tuo programma di esempio con assert. Non come funziona affermare se stesso. In che modo termina il programma in modo anomalo? genera una sorta di eccezione? Che tipo? Crea un segnale speciale? quale segnale? Le asserzioni possono essere "catturate" da qualsiasi tipo di meccanismo di prova del C ++?
Motti Shneor,

4

Cose come 'solleva eccezioni' e 'interrompe l'esecuzione' potrebbero essere vere per la maggior parte dei compilatori, ma non per tutti. (A proposito, ci sono affermazioni che fanno davvero eccezione?)

Ecco un significato interessante, leggermente diverso, di assert usato da c6x e altri compilatori TI: dopo aver visto certe affermazioni assert, questi compilatori usano le informazioni in quella affermazione per eseguire alcune ottimizzazioni. Wicked.

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

Questo dice al compilatore che le matrici sono allineate su limiti a 32 bit, quindi il compilatore può generare istruzioni specifiche fatte per quel tipo di allineamento.


1
Quindi cosa fanno se l'asserzione è falsa e NDEBUG non è impostato? Se questa è la versione di assert da <assert.h>, lo standard richiede che stampi un messaggio e si interrompa. Ovviamente lo standard non dice che non è possibile ottimizzare in base alla verità della dichiarazione, ma per essere conformi devono comunque interrompere se è falso.
Steve Jessop,

1
seguono il comportamento standard
stijn

1

Bozza standard C ++ 11 N3337

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

19.3 Asserzioni

1 L'intestazione <cassert>, descritta nella (Tabella 42), fornisce una macro per documentare le asserzioni del programma C ++ e un meccanismo per disabilitare i controlli delle asserzioni.

2 I contenuti sono gli stessi dell'intestazione della libreria C standard <assert.h>.

Tiraggio standard C99 N1256

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

7.2 Diagnostica <assert.h>

1 L'intestazione <assert.h>definisce la macro di asserzione e fa riferimento a un'altra macro, NDEBUGche non è definita da <assert.h>. Se NDEBUGè definito come un nome macro nel punto nel file di origine in cui è incluso <assert.h>, la macro assert è definita semplicemente come

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

La macro assert viene ridefinita in base allo stato corrente di NDEBUG ogni volta che <assert.h>viene inclusa.

2. La macro di asserzione deve essere implementata come una macro, non come una funzione effettiva. Se la definizione di macro viene soppressa per accedere a una funzione effettiva, il comportamento non è definito.

7.2.1 Diagnostica del programma

7.2.1.1 La macro assert

Sinossi

1.

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

Descrizione

2 La macro assert inserisce test diagnostici nei programmi; si espande in un'espressione vuota. Quando viene eseguito, se espressione (che deve avere un tipo scalare) è falsa (vale a dire, confronta uguale a 0), la macro assert scrive informazioni sulla chiamata particolare non riuscita (incluso il testo dell'argomento, il nome del file di origine, numero della riga di origine e nome della funzione che racchiude - questi ultimi sono rispettivamente i valori delle macro di preelaborazione __FILE__e __LINE__e dell'identificatore __func__) sul flusso di errori standard in un formato definito dall'implementazione. 165) Chiama quindi la funzione di interruzione.

ritorna

3 La macro assert non restituisce alcun valore.


1

Ci sono tre ragioni principali per usare la funzione assert () sulla normale if else e printf

  1. La funzione assert () viene utilizzata principalmente nella fase di debug, è noioso scrivere se altrimenti con un'istruzione printf ogni volta che si desidera verificare una condizione che potrebbe anche non farsi strada nel codice finale.

  2. Nelle distribuzioni di software di grandi dimensioni, assert è molto utile in cui è possibile fare in modo che il compilatore ignori le istruzioni assert utilizzando la macro NDEBUG definita prima di collegare il file di intestazione per la funzione assert ().

  3. assert () è utile quando si progetta una funzione o un codice e si vuole farsi un'idea di quali limiti il ​​codice funzionerà e non funzionerà e infine includere un if per la valutazione fondamentalmente giocando con i presupposti.


0

È una funzione che interrompe l'esecuzione del programma se il valore che ha valutato è falso. Di solito è circondato da una macro in modo che non venga compilato nel binario risultante quando viene compilato con le impostazioni di rilascio.

È progettato per essere utilizzato per testare le ipotesi formulate. Per esempio:

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

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

L'ideale che desideri è che puoi fare un errore nel tuo programma, come chiamare una funzione con argomenti non validi, e premi un'asserzione prima che segfault (o non funzioni come previsto)


perché non usiamo solo if & else e aggiungiamo alcune informazioni di registrazione?
Asad Khan,

1
Perché non dovresti mai passare un puntatore null a strcpy. È una di quelle cose che non dovrebbero accadere. Se è stato passato un puntatore null, significa che qualcosa a un livello superiore è incasinato. Nella migliore delle ipotesi si finisce per arrestare ulteriormente il programma dal problema a causa di valori di dati imprevisti (dest che non è corretto o null).
Yacoby,

-5

Inoltre, è possibile utilizzarlo per verificare se l'allocazione dinamica ha avuto esito positivo.

Esempio di codice:

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.

Simile a:

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

3
No. newgenera un'eccezione in caso di errore di allocazione a meno che non specifichi nothrow(cosa che non hai fatto qui). Inoltre, la tua formattazione è strana ed exitè cattiva.
Razze di leggerezza in orbita

Si hai ragione. Ho dimenticato di aggiungere di no. Mi piacerebbe vedere come userete invece di uscire
Sadikov

1
@Sadikov Qualcun altro gestirà tale condizione di errore utilizzando un codice che non viene completamente rimosso durante la creazione in modalità di rilascio , lasciando quindi gli utenti senza protezione e in balia di comportamenti indefiniti se una condizione preliminare non è soddisfatta e, grazie a ciò, è mai controllato e catturato . assert()serve solo per eseguire il debug e sradicare cose che non dovrebbero mai, mai, mai accadere - molto prima che venga realizzata una build di rilascio.
underscore_d
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.