Ajouter des messages personnalisés dans assert?


129

Existe-t-il un moyen d'ajouter ou de modifier le message lancé par assert? J'aimerais utiliser quelque chose comme

assert(a == b, "A must be equal to B");

Ensuite, le compilateur ajoute la ligne , l' heure et ainsi de suite ...

C'est possible?


Vous pouvez définir une macro, comme ceci .
— HelloGoodbye

Réponses:


240

Un hack que j'ai vu est d'utiliser l' &&opérateur. Étant donné qu'un pointeur «est vrai» s'il n'est pas nul, vous pouvez effectuer les opérations suivantes sans modifier la condition:

assert(a == b && "A is not equal to B");

Puisque assertmontre la condition qui a échoué, il affichera également votre message. Si cela ne suffit pas, vous pouvez écrire votre propre myAssertfonction ou macro qui affichera ce que vous voulez.


27
Une autre option consiste à inverser les opérandes et à utiliser l'opérateur virgule. Vous avez besoin de parenthèses supplémentaires pour que la virgule ne soit pas traitée comme un délimiteur entre les arguments:assert(("A must be equal to B", a == b));
— Keith Thompson

3
Ce serait bien, cependant, de pouvoir imprimer les valeurs des variables, comme dans:assert(a == b && "A (" << A << ") is not equal to B (" << B << ")");
— Frank

7
@Frank, printfrenvoie une valeur différente de zéro s'il imprimait quelque chose, vous pouvez donc faire quelque chose comme assert(a == b && printf("a (%i) is not equal to b (%i)", a, b)), bien qu'à ce stade, vous devriez probablement écrire votre propre wrapper d'assert.
— zneak

1
Mauvais code! Je ne comprends pas ça! Si a == b est faux, l'expression and doit également être fausse et, par conséquent, la chaîne ne doit pas être évaluée.
— ragnarius

1
@TUIlover, ce n'est pas ainsi que fonctionnent les littéraux de chaîne C; ce sont des constantes de compilation et leur utilisation dans ce contexte est optimisée de manière triviale. Il n'y a aucun coût d'exécution.
— zneak

45

Une autre option consiste à inverser les opérandes et à utiliser l'opérateur virgule. Vous avez besoin de parenthèses supplémentaires pour que la virgule ne soit pas traitée comme un délimiteur entre les arguments:

assert(("A must be equal to B", a == b));

(ceci a été copié à partir des commentaires ci-dessus, pour une meilleure visibilité)


3
C'est une excellente approche, avec un petit problème, il affichera "avertissement: l'opérande gauche de l'opérateur virgule n'a aucun effet" lorsqu'il est compilé en g ++ avec `-Wunused-value
— v010dya

1
ou avec une macro: #ifndef m_assert #define m_assert (expr, msg) assert ((msg, expr)) #endif
— Szymon Marczak

L'utilisation d'un wrapper de macro vous permet d'éviter l'avertissement gcc:#define m_assert(expr, msg) assert(( (void)(msg), (expr) ))
— Jander

25

Voici ma version de la macro assert, qui accepte le message et imprime tout de manière claire:

#include <iostream>

#ifndef NDEBUG
#   define M_Assert(Expr, Msg) \
    __M_Assert(#Expr, Expr, __FILE__, __LINE__, Msg)
#else
#   define M_Assert(Expr, Msg) ;
#endif

void __M_Assert(const char* expr_str, bool expr, const char* file, int line, const char* msg)
{
    if (!expr)
    {
        std::cerr << "Assert failed:\t" << msg << "\n"
            << "Expected:\t" << expr_str << "\n"
            << "Source:\t\t" << file << ", line " << line << "\n";
        abort();
    }
}

Maintenant, vous pouvez utiliser ceci

M_Assert(ptr != nullptr, "MyFunction: requires non-null argument");

Et en cas d'échec, vous recevrez un message comme celui-ci:

Échec de l'assertion: MyFunction: nécessite un argument non nul

Attendu: ptr! = Nullptr

Source: C: \ MyProject \ src.cpp, ligne 22

Agréable et propre, n'hésitez pas à l'utiliser dans votre code =)


Joli. Très utile
— Killrazor

Je suis un peu confus. #Expr est-il traité comme une chaîne de substitution directe? Quelle est la différence entre #Expr et Expr?
— Minh Tran

@MinhTran Supposons que votre condition d'assertion est x == y. Ensuite, Expr se développera if( !(x == y))et c'est là que la condition est vérifiée, et #Expr se développera en littéral de chaîne "x == y", que nous mettons ensuite dans un message d'erreur.
— Eugene Magdalits

Malheureusement, cette solution entraîne un comportement non défini en raison de l'utilisation d'identificateurs réservés.
— Rappelez

19
BOOST_ASSERT_MSG(expre, msg)

http://www.boost.org/doc/libs/1_51_0/libs/utility/assert.html

Vous pouvez soit l'utiliser directement, soit copier le code de Boost. Notez également que l'assertion de Boost est uniquement un en-tête, vous pouvez donc simplement récupérer ce fichier unique si vous ne souhaitez pas installer tout Boost.


@Jichao, qu'entendez-vous par implémentation de l'interface d'assert?
— Tarc

7

Comme la réponse de zneak complique quelque peu le code, une meilleure approche consiste simplement à commenter la chaîne de texte dont vous parlez. c'est à dire.:

assert(a == b); // A must be equal to B

Puisque le lecteur de l'erreur d'assertion recherchera de toute façon le fichier et la ligne à partir du message d'erreur, il verra l'explication complète ici.

Parce qu'en fin de compte, ceci:

assert(number_of_frames != 0); // Has frames to update

lit mieux que ça:

assert(number_of_frames != 0 && "Has frames to update");

en termes d'analyse humaine du code ie. lisibilité. Pas non plus un hack de langue.


1
"Puisque le lecteur de l'erreur d'assertion recherchera le fichier et la ligne de toute façon à partir du message d'erreur," - seulement s'ils sont diligents.
— Jason S du

Seulement s'ils veulent corriger le bogue, vous voulez dire ... quel commentaire idiot
— métamorphose

1
Non. Plus vous aidez les gens à voir le problème, plus ils auront de chances d'agir.
— Jason S du

hausser les épaules Pas d' accord.
— métamorphose du

2

assert est une combinaison macro / fonction. vous pouvez définir votre propre macro / fonction, en utilisant __FILE__, __BASE_FILE__, __LINE__etc, avec votre propre fonction qui prend un message personnalisé


-6

Pour vc, ajoutez le code suivant dans assert.h,

#define assert2(_Expression, _Msg) (void)( (!!(_Expression)) || (_wassert(_CRT_WIDE(#_Msg), _CRT_WIDE(__FILE__), __LINE__), 0) )

11
Modifier les en-têtes de votre compilateur est une mauvaise idée.
— Ross Ridge
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.