158
#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?

tvr
  • 4,315
  • 9
  • 22
  • 27
  • 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

195

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

Sean
  • 4,954
  • 2
  • 23
  • 21
  • 21
    Technically string concatenation is done at the language level. – Martin York Mar 10 '11 at 06:59
  • 53
    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
  • 9
    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
  • 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
  • 1
    @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
  • 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
129

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
  • 15,537
  • 3
  • 41
  • 64
  • 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
  • 5
    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
26

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
  • 354
  • 3
  • 4
  • 2
    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