C/C++ macro string concatenation C/C++ macro string concatenation c c

C/C++ macro string concatenation


If they're both strings you can just do:

#define STR3 STR1 STR2

This then expands to:

#define STR3 "s" "1"

and in the C language, separating two strings with space as in "s" "1" is exactly equivalent to having a single string "s1".


You don't need that sort of solution for string literals, since they are concatenated at the language level, and it wouldn't work anyway because "s""1" isn't a valid preprocessor token.

[Edit: In response to the incorrect "Just for the record" comment below that unfortunately received several upvotes, I will reiterate the statement above and observe that the program fragment

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

produces this error message from the preprocessing phase of gcc: error: pasting ""s"" and ""1"" does not give a valid preprocessing token

]

However, for general token pasting, try this:

/* * 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)

Then, e.g., both PPCAT_NX(s, 1) and PPCAT(s, 1) produce the identifier s1, unless s is defined as a macro, in which case PPCAT(s, 1) produces <macro value of s>1.

Continuing on the theme are these 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)

Then,

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

By contrast,

STRINGIZE(PPCAT_NX(T1, T2)) // produces "T1T2"STRINGIZE_NX(PPCAT_NX(T1, T2)) // produces "PPCAT_NX(T1, T2)"#define T1T2 visit the zooSTRINGIZE(PPCAT_NX(T1, T2)) // produces "visit the zoo"STRINGIZE_NX(PPCAT(T1, T2)) // produces "PPCAT(T1, T2)"


Hint: The STRINGIZE macro above is cool, but if you make a mistake and its argument isn't a macro - you had a typo in the name, or forgot to #include the header file - then the compiler will happily put the purported macro name into the string with no error.

If you intend that the argument to STRINGIZE is always a macro with a normal C value, then

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

will expand it once and check it for validity, discard that, and then expand it again into a string.

It took me a while to figure out why STRINGIZE(ENOENT) was ending up as "ENOENT" instead of "2"... I hadn't included errno.h.