Recherche…


Introduction

Une assertion est un prédicat que la condition présentée doit être vraie au moment où l'assertion est rencontrée par le logiciel. Les plus simples sont les assertions simples , validées au moment de l'exécution. Cependant, les assertions statiques sont vérifiées au moment de la compilation.

Syntaxe

  • affirmer (expression)
  • static_assert (expression, message)
  • _Static_assert (expression, message)

Paramètres

Paramètre Détails
expression expression de type scalaire.
message chaîne littérale à inclure dans le message de diagnostic.

Remarques

Les deux assert et static_assert sont des macros définies dans assert.h .

La définition de assert dépend de la macro NDEBUG qui n'est pas définie par la bibliothèque standard. Si NDEBUG est défini, assert est un no-op:

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

L'opinion varie selon que NDEBUG doit toujours être utilisé pour les compilations de production.

  • Le pro-camp soutient que assert appels abort et les messages d'affirmation ne sont pas utiles pour les utilisateurs finaux, de sorte que le résultat n'est pas utile à l' utilisateur. Si vous avez des conditions fatales à vérifier dans le code de production, vous devez utiliser les if/else ordinaires et exit ou quick_exit pour terminer le programme. Contrairement à l’ abort , elles permettent au programme de faire du nettoyage (via des fonctions enregistrées avec atexit ou at_quick_exit ).
  • Le con camp fait valoir que assert appels ne doivent jamais tirer dans le code de production, mais si elles le font, la condition est cochée, il y a quelque chose de mal et de façon spectaculaire le programme se conduisent mal pire si l' exécution se poursuit. Par conséquent, il est préférable d’avoir des assertions actives dans le code de la production car si elles se déclenchent, l’enfer est déjà déchaîné.
  • Une autre option consiste à utiliser un système d'assertions maison qui exécute toujours la vérification mais gère les erreurs différemment entre le développement (lorsque l' abort est approprié) et la production (où une «erreur interne inattendue - veuillez contacter le support technique» peut être plus appropriée).

static_assert développe en _Static_assert qui est un mot clé. La condition est vérifiée au moment de la compilation, la condition doit donc être une expression constante. Il n'est pas nécessaire que cela soit traité différemment entre le développement et la production.

Condition préalable et postcondition

Un cas d'utilisation pour l'assertion est la condition préalable et la post-condition. Cela peut être très utile pour maintenir invariant et concevoir par contrat . Pour un exemple, une longueur est toujours nulle ou positive, donc cette fonction doit renvoyer une valeur nulle ou positive.

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

Assertion simple

Une assertion est une déclaration utilisée pour affirmer qu'un fait doit être vrai lorsque cette ligne de code est atteinte. Les assertions sont utiles pour s'assurer que les conditions attendues sont remplies. Lorsque la condition passée à une assertion est vraie, il n'y a pas d'action. Le comportement sur les conditions fausses dépend des indicateurs du compilateur. Lorsque des assertions sont activées, une fausse entrée provoque un arrêt immédiat du programme. Lorsqu'elles sont désactivées, aucune action n'est entreprise. Il est courant d'activer les assertions dans les versions internes et de débogage, et de les désactiver dans les versions de publication, bien que les assertions soient souvent activées dans la version. (Le fait que la terminaison soit meilleure ou pire que les erreurs dépend du programme.) Les assertions ne doivent être utilisées que pour intercepter des erreurs de programmation internes, ce qui signifie généralement que des paramètres incorrects ont été transmis.

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

Sortie possible avec NDEBUG non défini:

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

Sortie possible avec NDEBUG défini:

x = -1

Il est NDEBUG définir NDEBUG globalement afin de pouvoir facilement compiler votre code avec toutes les assertions NDEBUG ou désactivées. Un moyen simple de le faire est de définir NDEBUG comme une option pour le compilateur ou de le définir dans un en-tête de configuration partagé (par exemple, config.h ).

Affirmation statique

C11

Les assertions statiques sont utilisées pour vérifier si une condition est vraie lorsque le code est compilé. Si ce n'est pas le cas, le compilateur doit émettre un message d'erreur et arrêter le processus de compilation.

Une assertion statique est une assertion qui est vérifiée au moment de la compilation, pas au moment de l'exécution. La condition doit être une expression constante et, si false, une erreur de compilation. Le premier argument, la condition qui est vérifiée, doit être une expression constante et le second un littéral de chaîne.

Contrairement à assert, _Static_assert est un mot-clé. Une macro de commodité static_assert est définie dans <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

Avant C11, il n'y avait pas de support direct pour les assertions statiques. Cependant, en C99, les assertions statiques pouvaient être émulées avec des macros qui déclencheraient un échec de compilation si la condition de compilation était fausse. À la différence de _Static_assert , le second paramètre doit être un nom de jeton approprié afin de pouvoir créer un nom de variable avec lui. Si l'assertion échoue, le nom de la variable apparaît dans l'erreur du compilateur, car cette variable a été utilisée dans une déclaration de tableau syntaxiquement incorrecte.

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

Avant C99, vous ne pouviez pas déclarer des variables à des emplacements arbitraires dans un bloc, vous devriez donc être extrêmement prudent lorsque vous utilisez cette macro, en vous assurant qu'elle apparaît uniquement lorsqu'une déclaration de variable serait valide.

Affirmation de code inaccessible

Au cours du développement, lorsque certains chemins de code doivent être empêchés d'atteindre le flux de contrôle, vous pouvez utiliser assert(0) pour indiquer qu'une telle condition est erronée:

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

    default:
        assert(0);
}

Chaque fois que l'argument de la macro assert() évalué faux, la macro écrit des informations de diagnostic dans le flux d'erreur standard, puis abandonne le programme. Ces informations incluent le fichier et le numéro de ligne de l'instruction assert() et peuvent être très utiles lors du débogage. Les assertions peuvent être désactivées en définissant la macro NDEBUG .

Une autre façon de terminer un programme en cas d'erreur est d'utiliser les fonctions de bibliothèque standard exit , quick_exit ou abort . exit et quick_exit prenez un argument qui peut être renvoyé à votre environnement. abort() (et donc assert ) peut être une terminaison très grave de votre programme, et certains nettoyages qui seraient normalement effectués à la fin de l'exécution peuvent ne pas être exécutés.

Le principal avantage d’ assert() est qu’il imprime automatiquement les informations de débogage. L'appel à abort() présente l'avantage de ne pas pouvoir être désactivé comme une assertion, mais cela risque de ne pas entraîner l'affichage d'informations de débogage. Dans certaines situations, l'utilisation des deux concepts peut être bénéfique:

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

Lorsque les assertions sont activées , l'appel assert() imprimera les informations de débogage et mettra fin au programme. L'exécution n'atteint jamais l'appel abort() . Lorsque les assertions sont désactivées , l'appel assert() ne fait rien et abort() est appelé. Cela garantit que le programme se termine toujours pour cette condition d'erreur; L'activation et la désactivation n'affectent que les effets de l'impression ou non de la sortie de débogage.

Vous ne devriez jamais laisser un tel assert dans le code de production, car les informations de débogage ne sont pas utiles pour les utilisateurs finaux et parce que abort est généralement une terminaison beaucoup trop sévère qui empêchent les gestionnaires de nettoyage qui sont installés pour la exit ou quick_exit à courir.

Assert Messages d'erreur

Un truc existe qui peut afficher un message d'erreur avec une assertion. Normalement, vous écrivez un code comme celui-ci

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

Si l'assertion a échoué, un message d'erreur ressemblerait à

L'assertion a échoué: p! = NULL, fichier main.c, ligne 5

Cependant, vous pouvez également utiliser un AND logique ( && ) pour donner un message d'erreur.

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

Maintenant, si l'assertion échoue, un message d'erreur indiquera quelque chose comme ceci

Echec de l'assertion: p! = NULL && "fonction f: p ne peut pas être NULL", fichier main.c, ligne 5

La raison pour laquelle cela fonctionne est qu'une chaîne littérale est toujours évaluée à zéro (true). L'ajout de && 1 à une expression booléenne n'a aucun effet. Ainsi, l'ajout de && "error message" n'a aucun effet, sauf que le compilateur affichera l'intégralité de l'expression ayant échoué.



Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow