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

Is it possible to concatenate STR1 and STR2, to "s1"? You can do this by passing args to another Macro function. But is there a direct way?

Neuron
  • 5,141
  • 5
  • 38
  • 59
tvr
  • 4,455
  • 9
  • 24
  • 29
  • Shouldn't it be #define STR3 STR1 ## STR2 – Shrinidhi Mar 10 '11 at 06:39
  • 1
    It shouldn't be either because that defines STR3 to be the preprocessing token STR1STR2. And passing args to another macro function doesn't help, because string literals can't be pasted together -- "s""1" is not a valid token. – Jim Balter Mar 10 '11 at 07:09

3 Answers3

221

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".

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
Sean
  • 5,290
  • 2
  • 24
  • 21
  • 25
    Technically string concatenation is done at the language level. – Martin York Mar 10 '11 at 06:59
  • 57
    The preprocessor does no such thing. It's the C language proper that treats adjacent string literals as if they were a single string literal. – Jim Balter Mar 10 '11 at 07:00
  • 11
    It's more than a technicality - you can't concatenate `L"a"` and `"b"` to get `L"ab"`, but you _can_ concatenate `L"a"` and `L"b"` to get `L"ab"`. – MSalters Mar 10 '11 at 08:59
  • 1
    This does not work if you try `#include STR3` with `STR3` being a valid header file. Does anyone know how to? – Zythos Nov 11 '20 at 16:37
  • 2
    @Zythos - you might want to post a separate question with some details about what you are trying to do, what you expect to happen, and what actually happens. – Sean Nov 12 '20 at 17:15
  • 1
    There is no space required. Consecutive string literal tokens are treated as one string object. Secondly, it is false. String literals are catenated in ISO C translation stage 6. In translation stages 3 to 5, they are separate. This matters because a string literal can be used in an `#include`. Thirdly, `"\xF" "F"` is not exactly equivalent to `"\xFF"`. – Kaz Feb 22 '21 at 15:16
  • What if they both are not string? like one string and other macro? – Sazzad Hissain Khan Mar 27 '23 at 11:00
  • 1
    @SazzadHissainKhan Your question is already answered: in the example here, STR1 and STR2 are macros (that evaluate to strings). "both strings" in the answer means both strings or macros that expand to strings, as opposed to some other token type like a number or a symbol. To concatenate tokens that aren't strings (or macros that expand to strings), see my answer. – Jim Balter Jul 13 '23 at 06:07
145

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 ## B
PPCAT_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 1
STRINGIZE(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 zoo
STRINGIZE(PPCAT_NX(T1, T2)) // produces "visit the zoo"
STRINGIZE_NX(PPCAT(T1, T2)) // produces "PPCAT(T1, T2)"
Jim Balter
  • 16,163
  • 3
  • 43
  • 66
  • 8
    Just for the record, `"s""1"` is valid in C (and C++). They are two tokens (string literals) that the compiler would concat itself and threat as one token. – Shahbaz Jul 31 '12 at 09:24
  • 6
    You misunderstand both my comment and the C language. I said `"s""1" isn't a valid token` -- that is correct; it is, as you say, *two* tokens. But tacking them together with ## would make them a *single* preprocessing token, not two tokens, and so the compiler would not do a concatenation, rather the lexer would reject them (the language requires a diagnostic). – Jim Balter Jul 31 '12 at 09:30
  • Uhm... question, why do you need to redefine `macro`, and on the second definition, I see nothing but just removal of the suffix? – mr5 Jul 21 '14 at 13:31
  • 8
    @mr5 Read the comments, carefully. Macro names passed as macro arguments are not expanded before being passed. They are, however, expanded in the body of the macro. So if A is defined as FRED, STRINGIZE_NX(A) expands to "A" but STRINGIZE(A) expands to STRINGIZE_NX(FRED) which expands to "FRED". – Jim Balter Jul 21 '14 at 19:25
  • @Jim Balter FYI, if A is defined as FRED then STRINGIZE_NX(A) still expands to "FRED". But in the above example if STRINGIZE_NX(PPCAT(T1,T2)) is used then the resulting string is "PPCAT(T1,T2)" and not the expected "s1".I am not able to understand why PPCAT(T1,T2) is not expanded when STRINGIZE_NX is used. Why do we need an extra indirection/nesting? – bharath Jan 09 '18 at 10:38
  • @bharath ' if A is defined as FRED then STRINGIZE_NX(A) still expands to "FRED".' -- No, it doesn't; why would it? If your compiler does that, then it's broken. – Jim Balter Jan 09 '18 at 16:31
  • 1
    @bharath *the resulting string is "PPCAT(T1,T2)"* -- as expected and desired. *and not the expected "s1"* -- not expected at all. *Why do we need an extra indirection/nesting?* -- Read the code comments, and my comment above with the 6 upvotes. Only the bodies of macros are expanded; outside of macro bodies, macro arguments between parentheses are *not* expanded before being passed to macros. So `STRINGIZE_NX(whatever occurs here)` expands to "whatever occurs here", regardless of any macro definitions for whatever, occurs, or here. – Jim Balter Jan 10 '18 at 23:42
  • @Jim Balter I tried the following example: #include #define STRINGIZE_NX(A) #A int main(int argc, char** argv) { char str1[] = STRINGIZE_NX(ALEX); printf ("Name %s", str1); return 0; } and printf returns "Name ALEX" not as "Name A". Please correct me if i am looking in wrong direction – bharath Jan 11 '18 at 12:23
  • 1
    @bharath Of course it doesn't print "Name A" -- A is the parameter name, not the argument to the macro, which is ALEX. You claimed `if A is defined as FRED then STRINGIZE_NX(A) still expands to "FRED"` -- that is false, and is nothing like your test. You're trying hard not to understand or get this right, and I'm not going to respond to you further. – Jim Balter Jan 11 '18 at 19:23
  • @JimBalter I got where I went wrong. Actually my comment should have been 'if A is defined as FRED then STRINGIZE_NX(FRED) still expands to "FRED".Thanks for clarifying and sorry for misleading comment. – bharath Jan 19 '18 at 13:50
28

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.

Jordan Brown
  • 374
  • 3
  • 4
  • 3
    Important observation, and +1 for proper use of the `,` operator. :) – Jesse Chisholm Sep 21 '15 at 21:20
  • 2
    There's no particular reason why the content of the string should be a valid C expression. If you want to do this, I advise giving it a different name, like STRINGIZE_EXPR. – Jim Balter Oct 26 '18 at 14:01
  • That trick may have worked in isolation. But it prevents the compiler from seeing a sequence of strings which it will concatenate. (resulting in sequences like `((1),"1") "." ((2),"2")` instead of just "1" "." "2") – automorphic Mar 06 '20 at 07:17
  • 2
    Just to clarify what automorphic is saying: with the original `STRINGIZE` definition, `"The value of ENOENT is " STRINGIZE(ENOENT)` works, whereas `"The value of ENOENT is" STRINGIZE_EXPR(X)` produces an error. – Jim Balter Jun 25 '20 at 21:53
  • In the above comment I meant `STRINGIZE_EXPR(ENOENT)` rather than `STRINGIZE_EXPR(X)`. – Jim Balter Jul 13 '23 at 06:27