web-dev-qa-db-fra.com

Concaténation de chaînes de macros C / C ++

#define STR1      "s"
#define STR2      "1"
#define STR3      STR1 ## STR2

Est-il possible de concaténer ont STR3 == "s1"? Vous pouvez le faire en passant des arguments à une autre fonction Macro. Mais existe-t-il un moyen direct?

103
tvr

Si ce sont deux chaînes, vous pouvez simplement faire:

#define STR3 STR1 STR2

Le préprocesseur concatène automatiquement les chaînes adjacentes.

EDIT:

Comme indiqué ci-dessous, ce n'est pas le préprocesseur mais le compilateur qui effectue la concaténation.

135
Sean

Vous n'avez pas besoin de ce type de solution pour les littéraux de chaîne, car ils sont concaténés au niveau de la langue. Cela ne fonctionnerait de toute façon pas car "s" "1" n'est pas un jeton de préprocesseur valide.

[Edit: En réponse au commentaire "Juste pour mémoire" incorrect ci-dessous, qui a malheureusement reçu plusieurs votes positifs, je vais réitérer la déclaration ci-dessus et observer que le fragment de programme

#define PPCAT_NX(A, B) A ## B
PPCAT_NX("s", "1")

produit ce message d'erreur à partir de la phase de prétraitement de gcc: erreur: coller "" s "" et "" 1 "" ne donne pas un jeton de prétraitement valide

]

Cependant, pour le collage de jetons en général, essayez ceci:

/*
 * Concatenate preprocessor tokens A and B without expanding macro definitions
 * (however, if invoked from a macro, macro arguments are expanded).
 */
#define PPCAT_NX(A, B) A ## B

/*
 * Concatenate preprocessor tokens A and B after macro-expanding them.
 */
#define PPCAT(A, B) PPCAT_NX(A, B)

Ensuite, par exemple, PPCAT_NX(s, 1) et PPCAT(s, 1) produisent l'identificateur s1, À moins que s ne soit défini comme une macro, auquel cas PPCAT(s, 1) produit <macro value of s>1.

Continuant sur le thème sont ces macros:

/*
 * Turn A into a string literal without expanding macro definitions
 * (however, if invoked from a macro, macro arguments are expanded).
 */
#define STRINGIZE_NX(A) #A

/*
 * Turn A into a string literal after macro-expanding it.
 */
#define STRINGIZE(A) STRINGIZE_NX(A)

Ensuite,

#define T1 s
#define T2 1
STRINGIZE(PPCAT(T1, T2)) // produces "s1"

Par contre,

STRINGIZE(PPCAT_NX(T1, T2)) // produces "T1T2"
STRINGIZE_NX(PPCAT_NX(T1, T2)) // produces "PPCAT_NX(T1, T2)"

#define T1T2 visit the Zoo
STRINGIZE(PPCAT_NX(T1, T2)) // produces "visit the Zoo"
STRINGIZE_NX(PPCAT(T1, T2)) // produces "PPCAT(T1, T2)"
97
Jim Balter

Astuce: La macro STRINGIZE ci-dessus est cool, mais si vous faites une erreur et que son argument n'est pas une macro - vous avez une faute de frappe dans le nom, ou vous avez oublié de #include Le fichier d'en-tête - alors le compilateur mettra volontiers le nom de macro supposé dans la chaîne sans erreur.

Si vous souhaitez que l'argument de STRINGIZE soit toujours une macro avec une valeur C normale, alors

#define STRINGIZE(A) ((A),STRINGIZE_NX(A))

le développera une fois et vérifiera sa validité, le jettera, puis le développera à nouveau dans une chaîne.

Il m'a fallu un certain temps pour comprendre pourquoi STRINGIZE(ENOENT) finissait par être "ENOENT" Au lieu de "2" ... Je n'avais pas inclus errno.h.

24
Jordan Brown