Qu'est-ce que la fonction «affirmer»?


262

J'ai étudié des tutoriels OpenCV et suis tombé sur la assertfonction; Qu'est ce que ça fait?


20
Remarquez la note de man assert: "assert () est implémenté comme une macro; si l'expression testée a des effets secondaires, le comportement du programme sera différent selon que NDEBUG est défini. Cela peut créer des Heisenbugs qui disparaissent lorsque le débogage est activé . "
Johannes Schaub - litb


35
@ S.Lott maintenant, les gens qui recherchent Google trouveront cette page comme l'un des meilleurs résultats de recherche, fournissant une bonne réponse évaluée par les pairs à leur question et faisant la promotion de Stack Overflow en même temps, c'est donc un +1 de ma part!
Matt Grum

6
C'est un -1 de moi. Le premier résultat de recherche devrait être la documentation que le PO aurait dû consulter en premier lieu.
Courses de légèreté en orbite le

9
@LightnessRacesinOrbit. Appelez-moi paresseux, mais je préfère utiliser les excellentes lectures condensées, résumées et expliquées de la documentation fournies par des utilisateurs SO bien informés comme vous. Mes sincères remerciements :)
Tyson Hilmer

Réponses:


298

assertmettra fin au programme (généralement avec un message citant l'instruction assert) si son argument s'avère faux. Il est couramment utilisé pendant le débogage pour faire échouer le programme plus clairement si une condition inattendue se produit.

Par exemple:

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

Vous pouvez également ajouter un message plus informatif à afficher en cas d'échec:

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

Ou bien comme ça:

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

Lorsque vous effectuez une génération de version (sans débogage), vous pouvez également supprimer la surcharge des assertinstructions d' évaluation en définissant la NDEBUGmacro, généralement avec un commutateur de compilation. Le corollaire de cela est que votre programme ne doit jamais compter sur l'exécution de la macro assert.

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

À partir de la combinaison du programme appelant abort () et n'ayant aucune garantie de faire quoi que ce soit, les assertions ne devraient être utilisées que pour tester des choses que le développeur a supposées plutôt que, par exemple, l'utilisateur saisissant un nombre plutôt qu'une lettre (qui devrait être traitées par d’autres moyens).


49
" assertlève généralement une exception" - en C ++ il ne lève pas "exception" qu'il appelle abandon ... c'est un peu différent.
Artyom

5
Je ne pense pas que cette réponse concerne les mêmes langages que la question est balisée (C et C ++). En C et C ++, assert ne déclenche pas d'exception, il a des parenthèses autour de son argument et le #caractère n'introduit pas de commentaire.
Steve Jessop

Voici vos options: Créez la communauté-wiki de réponse et éditez votre question en supprimant les vieux trucs, en demandant aux autres de placer les informations correctes. De cette façon, les votes négatifs n'affecteront pas votre représentant et les gens peuvent améliorer la réponse.
Johannes Schaub - litb

2
length> = 0 se révélera également faux si la longueur est NaN
Andreas

1
Actuellement, dans VS 2015, l'assertion avec un message d'erreur ne fonctionnera pas car elle est hors service. Ça devrait êtreassert("error message", expression)
Dooskington

102

La déclaration assert computer est analogue à la déclaration assurez-vous en anglais.


131
Enfin, pas tout à fait. «Assurez-vous que la lumière est éteinte» signifie «vérifiez la lumière et éteignez-la si elle est allumée», et non «voyez si la lumière est éteinte et sinon, explosez». Je dirais que «revérifier» est une traduction plus proche.
Luke Maurer

7
@Luke, qui illustre les merveilles de la langue anglaise, dans la mesure où la langue offre de nombreuses façons de dire la même chose. Mais considérons assert (longueur> 0). Nous pouvons donc traduire cela par "revérifiez la longueur est supérieure à zéro" ou "assurez-vous que la longueur est supérieure à zéro" . Bien que les deux options fonctionnent clairement, je préfère toujours la mienne;)
Blake7

4
Eh bien, mais l'autre interprétation est " faites en sorte que la longueur soit supérieure à zéro". Il y a donc un peu plus d'ambiguïté.
Luke Maurer

29
Il est plus proche du verbe anglais "assert"
Steve Carter

En effet, "assurez-vous" pourrait être interprété comme "vérifier, et si ce n'est pas ok, changer".
Erik Bongers

14

Jeter un coup d'œil à

Exemple de programme assert () en C ++

De nombreux compilateurs proposent une macro assert (). La macro assert () renvoie VRAI si son paramètre évalue VRAI et prend une sorte d'action si elle évalue FAUX. De nombreux compilateurs abandonnent le programme sur un assert () qui échoue; d'autres lèveront une exception

Une caractéristique puissante de la macro assert () est que le préprocesseur la réduit en aucun code si DEBUG n'est pas défini. C'est une grande aide pendant le développement, et lorsque le produit final est livré, il n'y a pas de pénalité de performance ni d'augmentation de la taille de la version exécutable du programme.

Par exemple

#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
Ne devrait pas être "si NDEBUG est défini"?
RichN

2
De quoi parlent "de nombreux compilateurs"? MSVC et GCC sont tous deux conformes à ces normes. Quels compilateurs non conformes: n'ont pas assert; n'imprime pas de message et abandonne lorsqu'une assertion échoue; utiliser DEBUG au lieu du NDEBUG approprié?
Steve Jessop

lmao, bien sûr, c'est un site Web appelé java-samples qui se trompe tellement.
underscore_d

6

La fonction assert () peut diagnostiquer les bogues du programme. En C, il est défini en <assert.h>et en C ++, il est défini en <cassert>. Son prototype est

void assert(int expression);

L'expression d'argument peut être tout ce que vous voulez tester - une variable ou n'importe quelle expression C. Si l'expression est évaluée à TRUE, assert () ne fait rien. Si l'expression est évaluée à FALSE, assert () affiche un message d'erreur sur stderr et abandonne l'exécution du programme.

Comment utilisez-vous assert ()? Il est le plus souvent utilisé pour traquer les bogues du programme (qui sont distincts des erreurs de compilation). Un bogue n'empêche pas un programme de compiler, mais il le fait donner des résultats incorrects ou ne pas fonctionner correctement (verrouillage par exemple). Par exemple, un programme d'analyse financière que vous écrivez peut parfois donner des réponses incorrectes. Vous pensez que le problème est dû au fait que la variable interest_rate prend une valeur négative, ce qui ne devrait jamais arriver. Pour vérifier cela, placez la déclaration

assert (taux_intérêt> = 0); aux emplacements du programme où taux d'intérêt est utilisé. Si la variable devient négative, la macro assert () vous alerte. Vous pouvez ensuite examiner le code approprié pour localiser la cause du problème.

Pour voir comment fonctionne assert (), exécutez l'exemple de programme ci-dessous . Si vous entrez une valeur différente de zéro, le programme affiche la valeur et se termine normalement. Si vous entrez zéro, la macro assert () force la fin anormale du programme. Le message d'erreur exact que vous verrez dépendra de votre compilateur, mais voici un exemple typique:

Échec de l'assertion: x, fichier list19_3.c, ligne 13 Notez que, pour que assert () fonctionne, votre programme doit être compilé en mode débogage. Reportez-vous à la documentation de votre compilateur pour plus d'informations sur l'activation du mode de débogage (comme expliqué dans un instant). Lorsque vous compilerez ultérieurement la version finale en mode édition, les macros assert () sont désactivées.

 int x;

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

 assert(x >= 0);

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

Entrez une valeur entière: 10

Vous avez entré 10.

Entrez une valeur entière: -1

Message d'erreur: arrêt anormal du programme

Votre message d'erreur peut différer, selon votre système et votre compilateur, mais l'idée générale est la même.


Vous avez expliqué comment votre exemple de programme fonctionne avec assert. Pas comment s'affirmer fonctionne. Comment se termine-t-il anormalement le programme? cela jette-t-il une sorte d'exception? Quel genre? Cela crée-t-il un signal spécial? quel signal? Les assertions peuvent-elles être "interceptées" par n'importe quel type de mécanisme try-catch C ++?
Motti Shneor

4

Des trucs comme «déclenche une exception» et «arrête l'exécution» peuvent être vrais pour la plupart des compilateurs, mais pas pour tous. (BTW, y a-t-il des déclarations assert qui lèvent vraiment des exceptions?)

Voici une signification intéressante et légèrement différente d'assertion utilisée par c6x et d'autres compilateurs TI: en voyant certaines instructions assert, ces compilateurs utilisent les informations de cette instruction pour effectuer certaines optimisations. Méchant.

Exemple en 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;
}

Cela indique au compilateur que les tableaux sont alignés sur des limites de 32 bits, de sorte que le compilateur peut générer des instructions spécifiques faites pour ce type d'alignement.


1
Alors, que font-ils si l'assertion est fausse et que NDEBUG n'est pas défini? S'il s'agit de la version d'assert de <assert.h>, la norme exige qu'il imprime un message et abandonne. Évidemment, la norme ne dit pas qu'ils ne sont pas autorisés à optimiser en fonction de la véracité de la déclaration, mais pour être conformes, ils doivent encore abandonner si c'est faux.
Steve Jessop

1
ils suivent un comportement standard
stijn

1

Projet standard C ++ 11 N3337

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

19.3 Assertions

1 L'en-tête <cassert>, décrit dans (Tableau 42), fournit une macro pour documenter les assertions de programme C ++ et un mécanisme pour désactiver les vérifications d'assertion.

2 Le contenu est le même que l'en-tête de la bibliothèque C standard <assert.h>.

Projet standard C99 N1256

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

7.2 Diagnostics <assert.h>

1 L'en-tête <assert.h>définit la macro d'assertion et fait référence à une autre macro, NDEBUGqui n'est pas définie par <assert.h>. Si NDEBUGest défini comme un nom de macro au point du fichier source où <assert.h> est inclus, la macro d'assertion est définie simplement comme

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

La macro d'assertion est redéfinie en fonction de l'état actuel de NDEBUG chaque fois qu'il <assert.h>est inclus.

2. La macro d'assertion doit être implémentée comme une macro et non comme une fonction réelle. Si la définition de macro est supprimée afin d'accéder à une fonction réelle, le comportement n'est pas défini.

7.2.1 Diagnostic du programme

7.2.1.1 La macro assert

Synopsis

1.

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

La description

2 La macro assert place les tests de diagnostic dans les programmes; il se développe en une expression vide. Lorsqu'elle est exécutée, si l'expression (qui doit avoir un type scalaire) est fausse (c'est-à-dire qu'elle est égale à 0), la macro d'assertion écrit des informations sur l'appel particulier qui a échoué (y compris le texte de l'argument, le nom du fichier source, le numéro de ligne source et le nom de la fonction englobante - ces derniers sont respectivement les valeurs des macros de prétraitement __FILE__et __LINE__et de l'identifiant __func__) sur le flux d'erreur standard dans un format défini par l'implémentation. 165) Il appelle ensuite la fonction d'abandon.

Retour

3 La macro d'assertion ne renvoie aucune valeur.


1

Il y a trois raisons principales d'utiliser la fonction assert () par rapport à la normale if else et printf

  1. La fonction assert () est principalement utilisée dans la phase de débogage, il est fastidieux d'écrire sinon avec une instruction printf chaque fois que vous voulez tester une condition qui pourrait même ne pas faire son chemin dans le code final.

  2. Dans les grands déploiements de logiciels, assert est très pratique où vous pouvez faire ignorer au compilateur les instructions assert à l'aide de la macro NDEBUG définie avant de lier le fichier d'en-tête pour la fonction assert ().

  3. assert () est pratique lorsque vous concevez une fonction ou du code et que vous souhaitez vous faire une idée des limites du code et qu'il ne fonctionnera pas et enfin inclure un if sinon pour l'évaluer en jouant essentiellement avec des hypothèses.


0

C'est une fonction qui arrêtera l'exécution du programme si la valeur qu'il a évaluée est fausse. Habituellement, il est entouré d'une macro afin qu'il ne soit pas compilé dans le binaire résultant lorsqu'il est compilé avec les paramètres de version.

Il est conçu pour être utilisé pour tester les hypothèses que vous avez faites. Par exemple:

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

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

L'idéal que vous voulez est que vous puissiez faire une erreur dans votre programme, comme appeler une fonction avec des arguments invalides, et que vous frappiez une assertion avant qu'elle ne se mette en défaut (ou ne fonctionne pas comme prévu)


pourquoi ne pas simplement utiliser if & else et ajouter des informations de journalisation?
Asad Khan

1
Parce que vous ne devriez jamais passer un pointeur nul à strcpy. C'est l'une de ces choses qui ne devraient pas se produire. Si un pointeur nul a été passé, cela indique que quelque chose à un niveau supérieur a foiré. Au mieux, vous finissez par devoir planter le programme plus loin du problème en raison de valeurs de données inattendues (dest étant incorrect ou nul).
Yacoby

-5

De plus, vous pouvez l'utiliser pour vérifier si l'allocation dynamique a réussi.

Exemple de code:

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.

Semblable à:

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

3
Non. newGénère une exception en cas d'échec d'allocation, sauf si vous le spécifiez nothrow(ce que vous n'avez pas fait ici). De plus, votre formatage est bizarre et exitmauvais.
Courses de légèreté en orbite le

Oui, tu as raison. J'ai oublié de ne pas ajouter.
J'adorerais

1
@Sadikov N'importe qui d'autre gérerait une telle condition d'erreur en utilisant du code qui n'est pas complètement supprimé lors de la construction en mode de libération , laissant ainsi vos utilisateurs sans protection et à la merci d'un comportement non défini si une condition préalable n'est pas remplie et, grâce à cela, est jamais vérifié et attrapé . assert()est uniquement destiné au débogage et à l'élimination de choses qui ne devraient jamais, jamais, jamais arriver - bien avant la création d'une version.
underscore_d
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.