Jetons de préprocesseur valides dans la concaténation de macros

J’ai essayé de comprendre les macros dans c en utilisant l’opérateur de préprocesseur de concaténation ## mais je me suis rendu compte que j’ai un problème avec les jetons. Je pensais que c’était facile, mais en pratique, ce n’est pas le cas.

La concaténation sert donc à concaténer deux jetons pour créer un nouveau jeton. ex: concaténer ( et ) ou int et *

j’ai essayé

 #define foo(x,y) x ## y foo(x,y) 

chaque fois que je lui donne des arguments, j’obtiens toujours une erreur en disant que le pasting both argument does not give a valid preprocessor token.

Par exemple, pourquoi concaténer foo(1,aa) donne 1aa ( quel type de jeton? Et pourquoi est-il valide ) alors que foo(int,*) j’ai une erreur.

Existe-t-il un moyen de savoir quels jetons sont valides ou est-il possible d’avoir un bon lien pour comprendre comment peut le clarifier dans mon esprit. (J’ai déjà googlé dans google et SO)

Qu’est-ce que je rate ?

Je serai reconnaissant.

La concaténation de jetons de préprocesseur sert à générer de nouveaux jetons, mais elle n’est pas capable de coller ensemble des constructions de langage arbitraires (conférer, par exemple, la documentation gcc ):

Cependant, deux jetons qui ne forment pas ensemble un jeton valide ne peuvent pas être collés ensemble. Par exemple, vous ne pouvez pas concaténer x avec + dans l’un ou l’autre ordre.

Donc, une tentative de macro qui fait un pointeur d’un type comme

 #define MAKEPTR(NAME) NAME ## * MAKEPTR(int) myIntPtr; 

est invalide, car int* représente deux jetons, pas un.

L’exemple du lien mentionné ci-dessus, cependant, montre la génération de nouveaux jetons:

  #define COMMAND(NAME) { #NAME, NAME ## _command } struct command commands[] = { COMMAND (quit), COMMAND (help), ... }; 

rendements:

  struct command commands[] = { { "quit", quit_command }, { "help", help_command }, ... }; 

La commande de jetons quit_command n’existait pas auparavant, mais elle a été générée via la concaténation de jetons.

Notez qu’une macro de la forme

 #define MAKEPTR(TYPE) TYPE* MAKEPTR(int) myIntPtr; 

est valide et génère en fait un type de pointeur hors TYPE , par exemple int* sur int .

Comme cela semble être un sharepoint confusion, la chaîne 1aa est un jeton de préprocesseur valide; c’est une instance de pp-number dont la définition est (§6.4.8 de la norme C actuelle):

  pp-number: digit . digit pp-number digit pp-number identifier-nondigit pp-number e sign pp-number E sign pp-number p sign pp-number P sign pp-number . 

En d’autres termes, un pp-number commence par un chiffre ou un . suivi d’un chiffre. Il peut ensuite contenir n’importe quelle séquence de chiffres, des “identifiants non identifiables” (c’est-à-dire des lettres, des tirets bas et autres éléments pouvant faire partie d’un identifiant) ou les lettres e ou p minuscule) suivi d’un signe plus ou moins.

Cela signifie que, par exemple, 0x1e+2 est un pp-number valide, alors que 0x1f+1 ne l’est pas (il s’agit de trois jetons). Dans un programme valide, chaque pp-number qui survit aux phases de pré-traitement doit respecter la syntaxe d’une représentation de constante numérique, ce qui signifie qu’un programme incluant le texte 0x1e+2 sera considéré comme invalide. La morale, s’il y en a une, est que vous devez utiliser généreusement les espaces; cela n’a aucun coût.

Le but de pp-number est d’inclure tout ce qui pourrait éventuellement être un nombre dans une version future de C. (N’oubliez pas que les nombres peuvent être suivis de suffixes alphabétiques indiquant les types et la signature, tels que 27LU ).

Cependant, int* n’est pas un jeton de préprocesseur valide. Il s’agit de deux jetons (comme -3 ) et ne peut donc pas être formé avec l’opérateur de concaténation de jetons.

Une autre conséquence étrange de la règle de collage de jetons est qu’il est impossible de générer le jeton valide ... par concaténation de jetons, car .. n’est pas un jeton valide. ( a##b##c doit être évalué dans un certain ordre, donc même si les trois macros du préprocesseur se développent en . .)

Enfin, les symboles de commentaire /* et // ne sont pas des jetons; les commentaires sont remplacés par des espaces avant la séparation du texte du programme en jetons. Donc, vous ne pouvez pas non plus produire de commentaire avec collage de jetons (du moins, pas dans un compilateur conforme).

Le jeton de prétraitement est défini par la grammaire du langage C, voir la section 6.4 de la norme actuelle:

 preprocessing-token: header-name identifier pp-number character-constant ssortingng-literal punctuator each non-white-space character that cannot be one of the above 

La signification de chacun de ces termes est définie ailleurs dans la grammaire. La plupart s’expliquent d’elles-mêmes; identifier signifie tout ce qui est un nom de variable valide (ou le serait si ce n’était pas un mot-clé), et pp-number inclut les constantes entières et à virgule flottante.

En Standard C, le résultat du collage de deux jetons de prétraitement doit être un autre jeton de prétraitement valide. Historiquement, certains pré-processeurs autorisaient un autre collage (ce qui équivaut à ne pas coller!), Mais cela crée de la confusion lorsque les gens comstacknt leur code avec un compilateur différent.