Concaténer int en chaîne à l'aide du préprocesseur C

90

J'essaie de comprendre comment je peux concaténer un #define'd int à une #define' d string en utilisant le préprocesseur C. Mon compilateur est GCC 4.1 sur CentOS 5. La solution devrait également fonctionner pour MinGW.

Je voudrais ajouter un numéro de version à une chaîne, mais la seule façon de le faire fonctionner est de faire une copie du numéro de version défini comme des chaînes.

La chose la plus proche que j'ai pu trouver était une méthode pour citer des arguments de macro, mais cela ne fonctionne pas pour #defines

Cela ne fonctionne pas.

#define MAJOR_VER 2
#define MINOR_VER 6
#define MY_FILE "/home/user/.myapp" #MAJOR_VER #MINOR_VER

Il ne fonctionne pas sans #s soit parce que les valeurs sont des nombres et il se développerait à "/home/user/.myapp" 2 6, ce qui est valide C .

Cela fonctionne, mais je n'aime pas avoir des copies des définitions de version parce que j'en ai également besoin en tant que nombres.

#define MAJOR_VER 2
#define MINOR_VER 6
#define MAJOR_VER_STR "2"
#define MINOR_VER_STR "6"
#define MY_FILE "/home/user/.myapp" MAJOR_VER_STRING MINOR_VER_STRING
jonescb
la source
3
Copie

Réponses:

168

Question préprocesseur classique C ...

#define STR_HELPER(x) #x
#define STR(x) STR_HELPER(x)

#define MAJOR_VER 2
#define MINOR_VER 6
#define MY_FILE "/home/user/.myapp" STR(MAJOR_VER) STR(MINOR_VER)

Le niveau supplémentaire d'indirection permettra au préprocesseur d'étendre les macros avant qu'elles ne soient converties en chaînes.

Lindydancer
la source
3
STR () dans ce cas donnera une chaîne étroite. Existe-t-il une variante pour convertir cela en une chaîne large?
gkns
4
Je ne pourrais pas dire combien de fois je l'ai googlé et copié à partir de cette réponse exacte, mais elle sera à deux chiffres
MightyPork
Le premier "STR_HELPER" est requis car '#' ne fonctionne qu'avec un argument de macro. Il m'a fallu un
certain
@clarkttfu, en quelque sorte - oui, #ne fonctionne qu'avec des arguments de macro. Cependant, la STR_HELPERmacro est nécessaire pour éviter de transformer la macro MAJOR_VERen chaîne "MAJOR_VAR", là où nous voulons que le résultat soit "2".
Lindydancer
12

Une méthode de travail consiste à écrire MY_FILE en tant que macro paramétrique:

#define MY_FILE(x,y) "/home..." #x #y

EDIT: Comme indiqué par "Lindydancer", cette solution ne développe pas les macros dans les arguments. Une solution plus générale est:

#define MY_FILE_(x,y) "/home..." #x #y
#define MY_FILE(x,y) MY_FILE_(x,y)
Giuseppe Guerrini
la source
1
À mon avis honnête, c'est la meilleure réponse, et elle est beaucoup plus simple que les autres suggestions. Je suis surpris qu'il n'ait pas obtenu une meilleure note!
osirisgothra
5
C'est une solution propre qui, malheureusement, ne fonctionne pas. Si l'argument passé à MY_FILEsont des macros, disons Aet B, cette macro se développera en "/home..." "A" "B".
Lindydancer
2

Vous pouvez le faire avec BOOST_PP_STRINGIZE :

#define MAJOR_VER 2
#define MINOR_VER 6
#define MY_FILE "/home/user/.myapp" BOOST_PP_STRINGIZE(MAJOR_VER) BOOST_PP_STRINGIZE(MINOR_VER)
Maxim Egorushkin
la source
28
Ça me fait sourire la façon dont les gens lancent Boost sur tout.
Frerich Raabe
4
@Frerich: Prenant votre argument à l'extrême, les gens devraient d'abord écrire leurs propres compilateurs en code machine brut, plutôt que de lancer g ++ sur tout ... Inutile de réinventer la roue. Les bons programmeurs écrivent du code, les grands réutilisent.
Maxim Egorushkin
@jonescb: ouvrez simplement l'en-tête boost et voyez par vous-même.
Maxim Egorushkin
10
Oui, je l'ai essayé. Cela a fonctionné, mais utiliser un en-tête Boost dans un programme C me semble un peu étrange.
jonescb
1
Oh, mon mauvais, je n'ai pas remarqué la Cbalise.
Maxim Egorushkin