# et ## dans les macros

#include  #define f(a,b) a##b #define g(a) #a #define h(a) g(a) int main() { printf("%s\n",h(f(1,2))); printf("%s\n",g(f(1,2))); return 0; } 

En regardant simplement le programme, on “pourrait” s’attendre à ce que la sortie soit la même pour les deux déclarations printf. Mais lors de l’exécution du programme, vous l’obtenez en tant que:

 bash$ ./a.out 12 f(1,2) bash$ 

Pourquoi est-ce?

Parce que c’est comme ça que le préprocesseur fonctionne.

Un simple ‘#’ créera une chaîne à partir de l’argument donné, quel que soit le contenu de cet argument, alors que le double ‘##’ créera un nouveau jeton en concaténant les arguments.

Essayez de regarder la sortie prétraitée (par exemple avec gcc -E ) si vous voulez mieux comprendre comment les macros sont évaluées.

L’occurrence d’un paramètre dans une macro de type fonction, sauf s’il s’agit de l’opérande de # ou ## , est développée avant de la remplacer et de réparsingr l’ensemble pour une expansion ultérieure. Comme le paramètre de g est l’opérande de # , l’argument n’est pas développé, mais immédiatement stratifié ( "f(1,2)" ). Le paramètre h n’étant pas l’opérande de # ni ## , l’argument est tout d’abord développé ( 12 ), puis substitué ( g(12) ), puis une nouvelle parsing et un développement ultérieur ( "12" ).

Vous trouverez ci-dessous quelques concepts liés à votre question:

Argument Prescan :

Les macro-arguments sont complètement développés avant d’ être substitués dans un corps de macro, à moins qu’ils ne soient enchaînés ou collés avec d’autres jetons. Après la substitution, le corps entier de la macro, y compris les arguments substitués, est à nouveau analysé afin de développer les macros. Le résultat est que les arguments sont analysés deux fois pour développer les appels de macro.

Ssortingngification

Lorsqu’un paramètre de macro est utilisé avec un ‘#’ initial, le préprocesseur le remplace par le texte littéral de l’argument actuel, converti en une constante de chaîne .

Collage de jetons / concaténation de jetons :

Il est souvent utile de fusionner deux jetons en un tout en développant les macros. Ceci est appelé collage de jetons ou concaténation de jetons . L’opérateur de prétraitement ‘##’ effectue le collage de jetons. Lorsqu’une macro est développée, les deux jetons situés de part et d’autre de chaque opérateur ‘##’ sont combinés en un seul jeton, qui remplace ensuite le ‘##’ et les deux jetons d’origine dans le développement de la macro.

Le processus détaillé de votre scénario est donc le suivant:

 h(f(1,2)) -> h(12) // f(1,2) pre-expanded since there's no # or ## in macro h -> g(12) // h expanded to g 12 // g expanded g(f(1,2)) -> "f(1,2)" //f(1,2) is literally ssortinggified because of the `#` in macro g. f(1,2) is NOT expanded at all.