65 votes

Pourquoi est-ce macro remplacé comme 20 au lieu de 10?

1. #define NUM 10
2. #define FOO NUM
3. #undef NUM
4. #define NUM 20
5. 
6. FOO

Quand je n'exécutez le préprocesseur, le fichier de sortie contient 20.

Cependant, ce que je comprends, le préprocesseur n'est tout simplement de remplacement de texte. Donc, c'est ce que je pense qui se passe (ce qui est évidemment faux, mais idky):

  1. NUM est définie comme 10.
  2. Par conséquent, dans la ligne 2, NUM, est remplacé comme 10. Alors maintenant, nous avons "#define FOO 10".
  3. NUM est pas défini.
  4. NUM est redéfini et maintenant, est de 20.
  5. TOTO est remplacé conformément à la ligne 2, qui était en avant de la ligne 4 de la redéfinition, et est 10.

Donc, je pense que la sortie doit être de 10 au lieu de 20. Peut rien expliquer d'où ça s'est mal passé?

64voto

Dave Points 10916

Le texte de remplacement est effectué que lorsque la macro est utilisée, non pas où vous avez écrit l' #define. Au point que vous utilisez FOO, il remplace FOO avec NUM et NUM est actuellement défini pour être 20.

57voto

rici Points 45980

Dans l'intérêt de la collecte de toutes les spécifications pertinentes de la norme, j'ai extrait cette information à partir d'un fil de commentaires, et ajout de la section C++ numéros, basé sur le projet de N4527 (le texte normatif est identique dans les deux normes). La norme(s) sont absolument clair sur le sujet.

  1. #define directives de préprocesseur ne subissent pas de macro de remplacement.

    (C11 §6.10¶7; C++ §16[rpc] ¶6): Le prétraitement des jetons à l'intérieur d'un prétraitement de la directive ne sont pas soumis expansion de macro, sauf indication contraire.

  2. Après une macro est remplacée par son texte de remplacement, le nouveau texte est remplacé. Préprocesseur jetons dans la zone de remplacement sont développés comme les macros si il y a un actif de la définition de macros pour le jeton à ce point dans le programme.

    (C11 §6.10.3¶9; C++ §16.3[rpc.remplacer] ¶9) Un prétraitement de la directive de la forme

    définit un objet, macro qui provoque par la suite, chaque instance du nom de la macro à être remplacé par la liste de remplacement de prétraitement des jetons qui constituent le reste de la directive. La liste de remplacement est alors remplacé pour plus de noms de macro comme spécifié ci-dessous.

  3. Une définition de macro est actif à partir de la ligne suivante de la # define jusqu'à un pour le nom de la macro, ou la fin du fichier.

    (C11 §6.10.3.5¶1; C++ §16.3.5[rpc.champ d'application] ¶1) Une définition de macro dure (indépendant de la structure de bloc) jusqu'à ce qu'un correspondant identifier replacement-list new-line directive rencontré, ou (si ce n'est rencontrés) jusqu'à la fin du prétraitement de l'unité de traduction. Les définitions de macros n'ont aucune signification après la traduction de la phase 4.

Si l'on regarde le programme:

nous voyons que la définition de la macro d' #define en ligne 1 dure exactement à la ligne 3. Il n'est pas remplaçable de texte dans ces lignes, de sorte que la définition n'est jamais utilisé; par conséquent, le programme est effectivement la même chose que:

#undef

Dans ce programme, à la troisième ligne, il y a une définition d'active pour #undef, avec le remplacement de liste #define NUM 10 #define FOO NUM #undef NUM #define NUM 20 FOO , et pour NUM, avec le remplacement de liste #define FOO NUM #define NUM 20 FOO . L' FOO est remplacé par son remplacement, il NUM, et puis c'est encore une fois analysés pour les macros, résultant en NUM être remplacé avec sa liste de remplacement 20. Ce remplacement s'est de nouveau remplacé, mais il n'y a pas les macros définies, de sorte que le résultat final est que le jeton 20 est à gauche pour le traitement dans la phase de traduction 5.

20voto

Jefffrey Points 31698

Dans:

FOO

le préprocesseur va le remplacer par NUM, il remplacera NUM avec ce qu'il est actuellement défini, 20.

Ces quatre premières lignes sont équivalentes à:

#define FOO NUM 
#define NUM 20

14voto

Matt McNabb Points 14273

La norme C11 dit (et les autres versions de C, et C++, dire de même):

Un prétraitement de la directive de la forme # define identifier replacement-list new-line définit un objet-comme macro qui provoque par la suite, chaque instance du nom de la macro à être remplacé par la liste de remplacement de prétraitement des jetons qui constituent le reste de la directive. La liste de remplacement est alors remplacé pour plus de noms de macro comme spécifié ci-dessous.

Toutefois, il a également dit dans une autre partie (grâce à rici pour le signaler).

Le prétraitement des jetons à l'intérieur d'un prétraitement de la directive ne sont pas soumis expansion de macro, sauf indication contraire.

Si une instance suivante du nom de la macro qui se trouve à l'intérieur d'un autre #define directive est en fait pas remplacé.

Votre ligne, #define FOO NUM définit que lorsque le jeton FOO est constaté plus tard (à l'extérieur de l'autre #define directive!), il sera remplacé par le jeton NUM .

Après un jeton est remplacé, en analysant de nouveau se produit, et si l' NUM est elle-même une macro, alors NUM est remplacé à ce point. (Et si ce NUM développe contient des macros , puis qui devient élargi , et ainsi de suite).

Si votre séquence d'étapes est:

  1. NUM défini comme 10
  2. FOO défini comme NUM
  3. NUM undefined et ré-défini comme 20
  4. FOO s'étend à d' NUM
  5. (rebalayage) NUM s'étend à d' 20

Ce comportement peut être vu dans un autre commune de préprocesseur astuce, pour tourner la définition de la valeur d'une macro dans une chaîne de caractères:

#define STR(X) #X
#define STR_MACRO(X) STR(X)
#define NUM 10

puts( STR_MACRO(NUM) );     // output: 10

Si nous avions écrit puts( STR(NUM) ) le résultat NUM.

La sortie de l' 10 est possible parce que, comme avant, le deuxième #define ici ne fait pas l'étendre STR. Donc, la séquence d'étapes dans le présent code est:

  1. STR(X) défini comme #X
  2. STR_MACRO(X) défini comme STR(X)
  3. NUM défini comme 10
  4. STR_MACRO et NUM sont à la fois étendues; le résultat est puts( STR(10) );
  5. (Rescan résultat de la dernière extension) STR(10) est élargi à d' "10"
  6. (Rescan résultat de la dernière extension) Aucune possibilité d'expansion.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X