web-dev-qa-db-fra.com

Stringification - comment ça marche?

Je le sais:

#define foo 4  
#define str(s) #s

avec str(foo) écrit: "foo", car stringify est exécuté en premier lieu de l'expansion du texte, mais ceci:

 #define xstr(s) str(s)
 #define str(s) #s
 #define foo 4

avec xstr(foo) écrit: "4".

Pourquoi? Quelles sont les étapes du processus?

49
Marco A.

Les étapes pertinentes de l'expansion des macros sont (selon C 2011 [n1570] 6.10.3.1 et C++ 1998 16.3.1):

  1. Jetons de processus précédés de # Ou ##.
  2. Appliquez le remplacement de macro à chaque argument.
  3. Remplacez chaque paramètre par le résultat correspondant du remplacement de macro ci-dessus.
  4. Nouvelle analyse pour plus de macros.

Ainsi, avec xstr(foo), nous avons:

  1. Le texte de remplacement, str(s), ne contient ni # Ni ##, Donc rien ne se passe.
  2. L'argument foo est remplacé par 4, C'est donc comme si xstr(4) avait été utilisé.
  3. Dans le texte de remplacement str(s), le paramètre s est remplacé par 4, Produisant str(4).
  4. str(4) est à nouveau analysé. (Les étapes résultantes produisent ”4”.)

Notez que le problème avec str(foo) est que l'étape 2, qui remplacerait foo par 4, Vient après l'étape 1, qui change l'argument en chaîne. À l'étape 1, foo est toujours foo; il n'a pas été remplacé par 4, le résultat est donc ”foo”.

C'est pourquoi une macro d'aide est utilisée. Il nous permet d'obtenir une étape 2, puis d'utiliser une autre macro pour effectuer l'étape 1.

55
Eric Postpischil

Premier cas

  1. Évaluer str(foo): remplacer str(foo) par #foo, C'est-à-dire "foo"

Deuxième cas

  1. Évaluer xstr(foo): remplacer xstr(foo) par str(<foo-value>), c'est-à-dire str(4)
  2. Évaluer str(4): remplacer str(4) par #4, C'est-à-dire "4"

Généralement,

le préprocesseur évalue les macro-fonctions développant les macro-variables, jusqu'à ce qu'il n'y ait rien à évaluer:

Si vous définissez

#define xstr(s) str(s) + 1
#define str(s) s + 1

dans le code suivant

#define foo 4

int main()
{
    std::cout << str(foo) << '\n' 
              << xstr(foo) << '\n' ;

} 

il évaluerait comme

Première chaîne

  1. Remplacez str(foo) par <foo-value> + 1, C'est-à-dire 4 + 1
  2. Rien de plus à substituer. Finition.

Et le résultat est 4 + 1

Deuxième chaîne

  1. Remplacez xstr(foo) par str(<foo-value>) + 1, c'est-à-dire str(4) + 1
  2. Remplacez str(4) par <4-value> + 1, C'est-à-dire 4 + 1
  3. Rien de plus à substituer.

Et le résultat est 4 + 1 + 1

13
Lol4t0