2009-11-20 12 views
2

J'essaie de faire quelque chose qui est conceptuellement similaire à ceci, mais ne peut pas sembler le faire fonctionner (erreur montrée à la fin) des idées?C Programmation: préprocesseur, macros comme des jetons

#include <stdio.h> 

int main(int argc , char const *argv[]) 
{ 
    int abc_def_ghi = 42; 
    #define SUFFIX ghi 
    #define VAR(prefix) prefix##_def_##SUFFIX 
    printf("%d\n" , VAR(abc)); 
    return 0; 
} 

// untitled:8: error: ‘abc_def_SUFFIX’ undeclared (first use in this function) 
+0

'const argv'? La première fois que je vois une telle chose! L'idée semble bien, mais je ne suis pas sûr que je l'aime: il rend 'principal' non-conforme et m'empêche de faire quelque chose que je n'ai jamais fait;) – pmg

+2

Ce n'est pas non-conforme. 'argv' peut être déclaré comme équivalent à' char * argv [] '(C99 5.1.2.2.1), et l'ajout de' const' ne change rien sauf ce que 'main()' est autorisé à faire avec il (sans un plâtre). Rappelez-vous qu'un pointeur vers un non-const peut être converti en un pointeur vers un const sans problème - jusqu'au fait que les valeurs de ces pointeurs se comparent égales (6.3.2.3/2). –

+0

Bien, merci Michael. C'est l'inverse (enlever 'const') qui le rendrait non-conforme. Je commence à aimer ça! – pmg

Répondre

10

Vous juste besoin indirection supplémentaire:

#include <stdio.h> 

int main(int argc , char const *argv[]) 
{ 
    int abc_def_ghi = 42; 
    #define SUFFIX ghi 
    #define VAR3(prefix, suffix) prefix##_def_##suffix 
    #define VAR2(prefix, suffix) VAR3(prefix, suffix) 
    #define VAR(prefix) VAR2(prefix, SUFFIX) 
    printf("%d\n" , VAR(abc)); 
    return 0; 
} 

Même si il semble redondant, ce n'est pas.

+0

Pourriez-vous expliquer pourquoi? – liori

+0

Il m'est un peu trop tard pour essayer de comprendre le Standardese pour '6.10.3.3 L'opérateur ##, mais cela explique pourquoi quelque part. (pdf @ http://www.open-std.org/JTC1/sc22/wg14/www/docs/n1401.pdf) – pmg

+1

Parce que la liste de remplacement d'une macro n'est pas elle-même soumise à un macro-remplacement avant que ses paramètres ne soient remplacés et # et # # opérateurs appliqués.Donc, dans le code de l'interrogateur, def_ # SUFFIX est remplacé par def_SUFFIX avant toute possibilité de remplacer SUFFIX par ghi. Dans le code de caf, quand 'suffix' est remplacé par' SUFFIX' dans VAR2, l'argument est d'abord soumis à la macro-expansion (6.10.3.1/1). Le résultat est 'VAR3 (abc, ghi)', ce qui donne 'abc_def_ghi'. Notez que 'VAR3 (abc, SUFFIX)' donnerait toujours 'abc_def_SUFFIX', car les paramètres suivant ## ne sont pas développés (aussi 6.10.2.1/1). –

7

L'idiome habituel pour utiliser correctement les opérateurs de pré-traitement de chaînage (#) ou de collage de jetons (##) consiste à utiliser un second niveau d'indirection. (What are the applications of the ## preprocessor operator and gotchas to consider?).

#define STRINGIFY2(x) #x 
#define STRINGIFY(x) STRINGIFY2(x) 

#define PASTE2(a, b) a##b 
#define PASTE(a, b) PASTE2(a, b) 

Puis:

int main(int argc , char const *argv[]) 
{ 
    int abc_def_ghi = 42; 
    #define SUFFIX ghi 
    #define VAR(prefix) PASTE(prefix, PASTE(_def_, SUFFIX)) 
    printf("%d\n" , VAR(abc)); 
    return 0; 
} 

devrait vous donner les résultats que vous recherchez. Fondamentalement, le traitement des opérateurs # et ## a lieu avant le remplacement de la macro. Ensuite, un autre cycle de remplacement de la macro se produit. Donc, si vous voulez que les macros soient utilisées avec ces opérations, vous devez utiliser un 1er niveau qui fait simplement le remplacement - sinon le chaînage ou le collage se produit en premier, et les macros ne sont plus des macros - stringizing/coller produit. Pour le dire plus directement - le premier niveau de macro permet le remplacement des paramètres de macro, alors le 2ème niveau de macro-remplacement fait l'opération stringify/token-paste.

+0

Wow, merci, le STRINGIFY résout aussi un autre problème que j'ai eu. –

0

Cela fonctionne avec des niveaux d'indirection suffisants. Alors que une autre réponse est beaucoup adéquate, je veux offrir ce morceau de code comme une démo:

#define SUFFIX ghi 

#define VAR1(prefix) prefix##_def_##SUFFIX 
VAR1(abc) 

#define VAR2_(prefix, sfx) prefix##_def_##sfx 
#define VAR2(prefix) VAR2_(prefix,SUFFIX) 
VAR2(abc) 

#define VAR3_(prefix, sfx) prefix##_def_##sfx 
#define VAR3x(prefix,sfx) VAR3_(prefix,sfx) 
#define VAR3(prefix) VAR3x(prefix,SUFFIX) 
VAR3(abc) 

Enregistrer c'est un fichier texte, x.c, et seulement préprocesseur.

gcc -E x.c 

Observez et réfléchissez. Je ne comprends pas tout à fait moi-même. Il suffit de passer deux heures à essayer d'obtenir une macro en utilisant stringify pour travailler. Il est intéressant de voir qu'une double indirection est parfois nécessaire.

+0

Je reçois abc_def_SUFFIX abc_def_SUFFIX abc_def_ghi D'après l'explication de Steve, il semble que cela a à voir avec l'ordre de remplacement macro. –