2016-09-04 3 views
11

S'il vous plaît expliquer le codeUtilisation de # dans une macro

#include <stdio.h> 
#define A(a,b) a##b 
#define B(a) #a 
#define C(a) B(a) 

main() 
{ 
printf("%s\n",C(A(1,2))); 
printf("%s\n",B(A(1,2))); 
} 

Sortie

A (1,2)

Je don ne comprends pas, comment le premier printf évaluer ates à 12? N'est-il pas similaire à la seconde, car la macro C est simplement un wrapper à la macro B?

+2

Voir http://stackoverflow.com/questions/14351971/what-does-x-inside-ac-macro-mean/14352054#14352054 et http://stackoverflow.com/questions/1489932/comment-concaténer-deux fois-avec-le-c-préprocesseur-et-élargir-une-macro-comme-dans-arg – Michael

Répondre

3

La confusion vient ici d'une règle simple.

Lors de l'évaluation d'une macro, le préprocesseur résout d'abord les macros dans les arguments transmis à la macro. Toutefois, dans un cas particulier, si un argument a la valeur # ou est adjacent à ##, il ne résout pas les macros dans ces arguments. Telles sont les règles.

Votre premier cas

C(A(1,2)) 

Le pré-processeur applique d'abord la macro C(a), qui est défini comme B(a). Il n'y a pas # ou ## à côté de l'argument dans la définition (aucun d'entre eux dans B(a) du tout), ainsi le pré-processeur doit résoudre des macros dans l'argument:

A(1,2) 

La définition de A(a,b) est a##b qui évalue en 12.

Après les macros dans les arguments de la C(a) macro sont évalués, la macro C devient:

C(12) 

Le pré-processeur résout l'C(a) macro qui, selon sa définition devient

B(12) 

Une fois cela fait, le pré-processeur évalue à nouveau les macros dans le résultat et applique la macro B(a), de sorte que le résultat devient

"12" 

Votre second cas

B(A(1,2)) 

Tout comme le premier cas, le pré-processeur applique d'abord la B(a) macro. Mais cette fois, la définition de la macro est telle que l'argument est précédé de #. Par conséquent, la règle spéciale s'applique et les macros à l'intérieur de l'argument sont et non évaluée.Par conséquent, le résultat devient immédiatement:

"A(1,2)" 

Le préprocesseur va sur le résultat à nouveau en essayant de trouver plus des macros pour développer, mais maintenant tout est une partie de la chaîne, et les macros ne sont pas remplacées dans les chaînes. Ainsi, le résultat final est:

"A(1,2)" 
+0

Merci @ PineForestRanch, je l'ai maintenant compris. – user3612463

3

Le préprocesseur C a deux opérateurs # et ##. L'opérateur # transforme l'argument d'une fonction comme macro en une chaîne entre guillemets où l'opérateur ## concatène deux identifiants.

#define A(a,b) a##b will concatenate a with b returning ab as string. 
so A(1,2) will return 12 
#define B(a) #a will return a as string 
#define C(a) B(a) will call previous one and return a as string. 
so C(A(1,2)) = C(12) = B(12) = 12 (as string) 
B(A(1,2)) = A(1,2) because A(1,2) is taken as an argument and returned as string A(1,2) 
2

Il y a deux opérateurs utilisés dans les macros de type fonction:

  • ## provoque une macro pour concaténer deux paramètres.
  • # provoque la transformation de l'entrée en chaîne littérale.

En A(a,b)## provoque la concaténation de a avec b. Dans B(a), # crée effectivement un littéral de chaîne à partir de l'entrée. Ainsi, l'expansion se déroule comme suit:

C(A(1,2)) -> C(12) -> B(12) -> "12" 
B(A(1,2)) -> "A(1,2)" 

Parce que pour C(A(1,2)), la partie A(1,2) est évaluée en premier à se transformer en 12, les deux déclarations ne sont pas égaux comme ils semblent être.

Vous pouvez en savoir plus à ce sujet au cppreference.

+0

Merci pour la réponse @ js441 – user3612463

5

Comme mentionné dans Wikipedia C-preprocessor:

L'opérateur ## (connu sous le nom « jeton opérateur collage ») concatène deux jetons en un seul jeton.

L'opérateur # (connu sous le nom de "Stringification Operator") convertit un jeton en une chaîne, échappant de manière appropriée à toute citation ou antislash.

Si vous voulez stringify l'expansion d'un argument macro, vous avez d'utiliser deux niveaux de macros:

Vous ne pouvez pas combiner un argument macro avec un texte supplémentaire et stringify tous ensemble. Vous pouvez cependant écrire une série de constantes string adjacentes et des arguments stringifiés: le compilateur C combinera alors toutes les constantes de chaîne adjacentes en une longue chaîne.

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

str (foo) // outputs "foo" 
xstr (foo) // outputs "4" 

Aussi, from C-FAQ Question 11.17:

Il se trouve que la définition de # dit qu'il est censé stringize un argument macro immédiatement, sans augmenter plus loin, il (si l'argument arrive être le nom d'une autre macro).

Ainsi, de même, va dans ce sens:

you're doing C(A(1,2)), 
which would roll to C(12), // since no #, so inner argument is expanded 
and then to B(12) 
// [since you've done two levels of macros in the code: 
// 1. from C() to B(), and then, 2. B() to #a] 
= 12 . 

considérant que, dans le premier cas, seulement 1 niveau de mise en chaîne est clairement fait selon la définition de B (a) (car il se de chaîne de caractères immédiatement à cause de #)

macro-replacement of B(A(1,2)) 
= stringification of A(1,2) 
= A(1,2). 
+1

Merci @Am_I_Helpful en effet votre utile :) – user3612463