Pourquoi assert est-il une macro et non une fonction?

mon conférencier m'a demandé cela en classe, et je me demandais pourquoi c'était une macro au lieu d'une fonction?

56
demandé sur Yu Hao 2014-08-13 15:58:15

5 réponses

la simple explication serait que la norme exige que assert soit une macro, si nous regardons le projet de norme C99 ( autant que je peux dire les sections sont les mêmes dans projet de norme C11 ainsi que ) section 7.2 Diagnostics paragraphe 2 dit:

L'assertion de la macro doit être mis en œuvre comme un macro, pas comme un réel fonction. Si la macro définition est supprimée afin d'accéder à un fonction actuelle, le comportement n'est pas défini.

pourquoi cela est-il nécessaire, la raison donnée dans raison d'être de la norme internationale-langages de programmation-C est:

il peut être difficile ou impossible de faire affirmer une vraie fonction, donc il est limité à macro forme.

ce qui n'est pas très informatif, mais nous pouvons voir d'autres exigences pourquoi. Retour à la section 7.2 paragraphe 1 dit:

[...] Si NDEBUG est défini comme un nom macro au point du fichier source où est inclus, la macro assert est défini simplement comme

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

la macro affirmation est redéfinie en fonction de L'état actuel de NDEBUG chaque fois qui est inclus.

c'est important car il nous permet un moyen facile de désactiver les assertions en mode Version où vous pourriez vouloir prendre le coût de contrôles potentiellement coûteux.

et la deuxième exigence importante est qu'il est nécessaire d'utiliser les macros __FILE__ , __LINE__ et __func__ , qui est couvert dans la section 7.2.1.1 l'affirmation macro qui dit:

[...] la macro assert écrit des informations sur l'appel particulier qui a échoué [...] ces dernières sont respectivement les valeurs de prétraitement des macros _ _ fichier _ _ _ et _ _ ligne _ _ _ et de l'identificateur __func_ _) sur le flux d'erreurs standard dans un format défini par la mise en œuvre. 165) il appelle alors la fonction d'annulation.

où la note de bas de page 165 dit:

le message écrit pourrait être de la forme:

Assertion failed: expression, function abc, file xyz, line nnn.

L'avoir comme macro permet les macros __FILE__ etc... pour être évalué à l'endroit approprié et comme Joachim souligne être une macro lui permet d'insérer l'expression originale dans le message qu'il génère.

le projet de norme C++ exige que le contenu de l'en-tête cassert soit le même que celui du assert.h ." en-tête de la bibliothèque Standrd C:

le contenu est le même que l'en-tête Standard de la bibliothèque C.

voir aussi: ISO C 7.2.

pourquoi (nul) 0?

Pourquoi utiliser (void)0 par opposition à une autre expression qui ne fait rien? Nous pouvons trouver quelques raisons, d'abord c'est comment le synopsis d'assert semble dans la rubrique 7.2.1.1 :

void assert(scalar expression);

et il dit ( c'est moi qui souligne ):

l'assert macro met les tests de diagnostic dans les programmes; il se développe à une expression de vide.

l'expression (void)0 est compatible avec la nécessité de se retrouver avec une expression vide .

en supposant que nous l'avons fait en l'absence de cette exigence, d'autres expressions possibles pourraient avoir des effets indésirables tels que permettre des utilisations de assert en mode de publication qui ne seraient pas autorisées en mode de débogage par exemple en utilisant Uni 0 nous permettrait d'utiliser assert dans une affectation et lorsque utilisé correctement serait susceptible de générer un avertissement expression result unused . Quant à l'utilisation d'un énoncé composé comme un commentaire suggère, nous pouvons voir de C macro multi-ligne: do / while(0) vs scope bloque qu'ils ont des effets indésirables dans certains cas.

69
répondu Shafik Yaghmour 2017-05-23 12:10:19
  1. il permet de capturer le fichier (par __FILE__ ) et le numéro de ligne (par __LINE__ )
  2. il permet de substituer le assert à une expression valide qui ne fait rien (i.e. ((void)0) ) lors de la construction en mode de libération
44
répondu Robert Allan Hennigan Leahy 2014-08-14 00:43:34

cette macro est désactivée si, au moment de l'inclusion , une macro avec le nom de NDEBUG a déjà été définie. Cela permet à un codeur d'inclure autant d'appels d'assert que nécessaire dans un code source pendant le débogage du programme et ensuite de les désactiver tous pour la version de production en incluant simplement une ligne comme:

#define NDEBUG 

au début de son code, avant l'inclusion de <assert.h> .

donc, cette macro est conçu pour capturer les erreurs de programmation, pas les erreurs d'utilisateur ou d'exécution, car il est généralement désactivé après qu'un programme sort de sa phase de débogage.


le faire comme fonction va augmenter certains appels de fonction et vous ne pouvez pas contrôler toutes ces assertions en mode release.

si vous utilisez la fonction, alors _FILE__ , __LINE__ et __func__ donneront la valeur du code de cette fonction d'assertion. Pas que le fait d'appeler ligne ou ligne de la fonction d'appel.

13
répondu Jeegar Patel 2014-08-13 12:26:48

certaines assertions peuvent être coûteuses à appeler. Vous venez d'écrire une routine d'inversion matricielle haute performance, et vous ajoutez un contrôle de santé mentale

assert(is_identity(matrix * inverse))

jusqu'à la fin. Eh bien, votre matrices sont assez grandes, et si assert est une fonction, il faudrait beaucoup de temps pour faire le calcul avant de la passer dans l'affirmer. Temps vous ne voulez vraiment pas à passer si vous ne faites pas de débogage.

Ou peut-être l'affirmation est relativement bon marché, mais il est contenu dans une fonction très courte qui sera appelée dans une boucle interne. Ou d'autres circonstances similaires.

en faisant assert une macro à la place, vous pouvez éliminer le calcul entièrement lorsque les assertions sont désactivées.

13
répondu Hurkyl 2014-08-13 14:56:14

pourquoi affirmer une macro et non une fonction?

parce qu'il devrait être compilé en mode DEBUG et ne devrait pas être compilé en mode RELEASE .

1
répondu Amir Saniyan 2014-08-21 05:53:56