Essayer de comprendre le préprocesseur C
-
17-09-2020 - |
Question
Pourquoi ces blocs de code à des résultats différents?
Certains de code commune:
#define PART1PART2 works
#define STRINGAFY0(s) #s
#define STRINGAFY1(s) STRINGAFY0(s)
cas 1:
#define GLUE(a,b,c) a##b##c
STRINGAFY1(GLUE(PART1,PART2,*))
//yields
"PART1PART2*"
cas 2:
#define GLUE(a,b) a##b##*
STRINGAFY1(GLUE(PART1,PART2))
//yields
"works*"
cas 3:
#define GLUE(a,b) a##b
STRINGAFY1(GLUE(PART1,PART2*))
//yields
"PART1PART2*"
Je suis à l'aide de MSVC++ à partir de VS.net 2005 sp1
Edit:actuellement, il est ma conviction que le préprocesseur les œuvres de ce genre lors de l'expansion des macros:Étape 1:- prendre le corps - supprimer tout l'espace autour d' ## les opérateurs - analyser la chaîne, dans le cas d'un identificateur est trouvé qui correspond au nom d'un paramètre:-si c'est à côté d'un ## opérateur, remplacer l'identifiant à la valeur littérale du paramètre (c'est à direla chaîne de caractères passée en) -si elle n'est PAS à côté d'un ## opérateur, exécuter toute cette explication sur la valeur du paramètre d'abord, puis de remplacer l'identifiant à ce résultat.(en ignorant les stringafy unique '#' cas atm) -supprimer tous les ## les opérateurs
Étape 2:- prendre que la chaîne résultante et l'analyse de toutes les macros
maintenant, à part que je crois que tous les 3 cas devrait produire exactement la même chaîne résultante:
PART1PART2*
et donc après l'étape 2 de suite dans
œuvres*
mais à tout le moins, devrait aboutir à la même chose.
La solution
les cas 1 et 2 n'ont pas défini de comportement depuis votre tente de coller un *
dans un préprocesseur jeton.Selon les règles d'association de votre préprocesseur ce soit essaie de coller ensemble les jetons PART1PART2
(ou tout simplement PART2
) et *
.Dans votre cas, c'est probablement ce qui échoue silencieusement, qui est l'un des résultats possibles quand les choses ne sont pas définis.Le jeton PART1PART2
suivie par *
ne seront pas considérés comme des macro-expansion de nouveau.Stringfication donne le résultat que vous voyez.
Mon gcc se comporte différemment sur votre exemples:
/usr/bin/gcc -O0 -g -std=c89 -pedantic -E test-prepro.c
test-prepro.c:16:1: error: pasting "PART1PART2" and "*" does not give a valid preprocessing token
"works*"
Donc, pour résumer votre cas 1 a deux problèmes.
- Collage de deux jetons qui n'étaient pas le résultat valide préprocesseur jeton.
- ordre d'évaluation de la
##
opérateur
Dans le cas 3, votre compilateur est de donner un mauvais résultat.Il devrait
- évaluer les arguments pour
STRINGAFY1
- pour cela, il doit développer
GLUE
GLUE
résultats dansPART1PART2*
- qui doit être élargi encore
- le résultat est
works*
- qui est ensuite passé à
STRINGAFY1
Autres conseils
Cela fait exactement ce que vous dites de le faire.Les premier et seconde prennent les noms de symboles passés et collez-les dans un nouveau symbole.Le troisième prend 2 symboles et les colle, puis vous placez le * dans la chaîne vous-même (ce qui sera éventuellement évalué dans quelque chose d'autre.)
Quelle est exactement la question avec les résultats?Qu'attendez-vous d'obtenir?Tout semble fonctionner comme je m'y attendrais.
Alors bien sûr, c'est la question de savoir pourquoi jouez-vous avec les arts sombres du symbole muning comme celui-ci de toute façon?:)