Qu'est-ce que cette ligne signifie? Surtout, qu'est-ce que ##
moyenne?
[.____] # définir l'analyse (variable, drapeau) ((quelque chose. ## variable) & (drapeau)) [.____]
Éditer:
Un peu confus encore. Quel sera le résultat sans ##
?
Un peu confus encore. Que sera le résultat sans ##?
Habituellement, vous ne remarquerez aucune différence. Mais là est une différence. Supposons que Something
est de type:
struct X { int x; };
X Something;
Et regarde:
int X::*p = &X::x;
ANALYZE(x, flag)
ANALYZE(*p, flag)
Sans opérateur de concaténation jeton ##
, il se développe à:
#define ANALYZE(variable, flag) ((Something.variable) & (flag))
((Something. x) & (flag))
((Something. *p) & (flag)) // . and * are not concatenated to one token. syntax error!
Avec une concaténation jeton, il se développe à:
#define ANALYZE(variable, flag) ((Something.##variable) & (flag))
((Something.x) & (flag))
((Something.*p) & (flag)) // .* is a newly generated token, now it works!
Il est important de se rappeler que le préprocesseur fonctionne sur des jetons de préprocesseur, non sur texte. Donc, si vous voulez concaténer deux jetons, vous devez explicitement le dire.
##
s'appelle la concaténation de jetons, utilisée pour concaténer deux jetons dans une invocation macro.
Regarde ça:
Une partie très importante est que cette concaténation de jeton suit des règles très spéciales:
par exemple. IBM DOC:
Des exemples sont également très auto-expliqués
#define ArgArg(x, y) x##y
#define ArgText(x) x##TEXT
#define TextArg(x) TEXT##x
#define TextText TEXT##text
#define Jitter 1
#define bug 2
#define Jitterbug 3
Avec sortie:
ArgArg(lady, bug) "ladybug"
ArgText(con) "conTEXT"
TextArg(book) "TEXTbook"
TextText "TEXTtext"
ArgArg(Jitter, bug) 3
La source est la documentation IBM. Peut varier avec d'autres compilateurs.
à votre ligne :
Il concaténe l'attribut variable au "quelque chose". et adresse une variable logiquement andé qui donne en résultat si quelque chose.Viaable a un jeu de drapeaux.
Donc, un exemple de mon dernier commentaire et de votre question (compiler avec g ++):
// this one fails with a compiler error
// #define ANALYZE1(variable, flag) ((Something.##variable) & (flag))
// this one will address Something.a (struct)
#define ANALYZE2(variable, flag) ((Something.variable) & (flag))
// this one will be Somethinga (global)
#define ANALYZE3(variable, flag) ((Something##variable) & (flag))
#include <iostream>
using namespace std;
struct something{
int a;
};
int Somethinga = 0;
int main()
{
something Something;
Something.a = 1;
if (ANALYZE2(a,1))
cout << "Something.a is 1" << endl;
if (!ANALYZE3(a,1))
cout << "Somethinga is 0" << endl;
return 1;
};
permet de considérer un exemple différent:
envisager
#define MYMACRO(x,y) x##y
sans le ##
, clairement le préprocesseur ne peut pas voir x
et y
comme jetons séparés, peut-il?
Dans votre exemple,
#define ANALYZE(variable, flag) ((Something.##variable) & (flag))
##
n'est tout simplement pas nécessaire car vous ne faites aucun nouvel identifiant. En fait, des problèmes de compilateur "Erreur: coller". "Et" variable "ne donne pas de jeton de prétraitement valide"
Ce n'est pas une réponse à votre question, juste un message CW avec quelques conseils pour vous aider à explorer vous-même le préprocesseur.
L'étape de prétraitement est réellement effectuée avant tout code réel compilé. En d'autres termes, lorsque le compilateur commence à construire votre code, non # Définir Des déclarations ou quelque chose comme ça est laissé.
Un bon moyen de comprendre ce que le préprocesseur fait à votre code est de faire la maintien de la sortie prétraitée et de le regarder.
Voici comment le faire pour Windows :
Créez un fichier simple appelé test.cpp et mettez-le dans un dossier, dites c:\temp. Le mien ressemble à ceci:
#define dog_suffix( variable_name ) variable_name##dog
int main()
{
int dog_suffix( my_int ) = 0;
char dog_suffix( my_char ) = 'a';
return 0;
}
Pas très utile, mais simple. Ouvrez l'invite de commande Visual Studio, accédez au dossier et exécutez la commande suivante:
c:\temp>cl test.cpp /P
Donc, c'est le compilateur de votre fonctionnement (CL.EXE), avec votre fichier et l'option/P indique au compilateur de stocker la sortie prétraitée dans un fichier.
Maintenant, dans le dossier à côté de Test.CPP, vous trouverez Test.I, lequel pour moi ressemble à ceci:
#line 1 "test.cpp"
int main()
{
int my_intdog = 0;
char my_chardog = 'a';
return 0;
}
Comme vous pouvez le voir, non # Définir à gauche, seul le code qu'il s'est étendu à.
Selon Wikipedia
La concaténation de jetons, également appelée jeton collant, est l'un des caractéristiques les plus subtiles - et les plus faciles à abuser du préprocesseur de macro. Deux arguments peuvent être "collés" ensemble en utilisant l'opérateur de préprocesseur; Cela permet à deux jetons d'être concaténés dans le code prétraité. Cela peut être utilisé pour construire des macros élaborées qui agissent comme une version brute de modèles C++.
Chèque concaténation de jeton