110

I'm trying to figure out how I can concatenate a #define'd int to a #define'd string using the C Preprocessor. My compiler is GCC 4.1 on CentOS 5. The solution should also work for MinGW.

I'd like to append a version number onto a string, but the only way I can get it to work is to make a copy of the version number defines as strings.

The closest thing I could find was a method of quoting macro arguments, but it doesn't work for #defines

This is does not work.

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

It doesn't work without the #s either because the values are numbers and it would expand to "/home/user/.myapp" 2 6, which isn't valid C.

This does work, but I don't like having copies of the version defines because I do need them as numbers as well.

#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
jww
  • 97,681
  • 90
  • 411
  • 885
jonescb
  • 22,013
  • 7
  • 46
  • 42

3 Answers3

227

Classical C preprocessor question....

#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)

The extra level of indirection will allow the preprocessor to expand the macros before they are converted to strings.

Lindydancer
  • 25,428
  • 4
  • 49
  • 68
  • 4
    STR() in this case will give a Narrow string. Is there a variation to convert this to a wide string? – gkns Aug 25 '16 at 08:57
  • 10
    I couldn't say how many times I googled it and copied from this exact answer, but it's going to be in double digits – MightyPork Dec 14 '18 at 19:04
  • 2
    The first "STR_HELPER" is required because '#' only works with a macro argument. It took me sometime to figure that out.. – clarkttfu May 14 '20 at 09:30
  • 1
    @clarkttfu, sort of -- yes, `#` only works with macro arguments. However, the `STR_HELPER` macro is needed to avoid turning the macro `MAJOR_VER` into the string `"MAJOR_VAR"`, wheres we want to the result to be `"2"`. – Lindydancer May 14 '20 at 15:28
  • My brain hurts that this can't be done with a single macro... As a lot of other people, used this dozens of times – Andrejs Gasilovs Sep 14 '21 at 10:03
15

A working way is to write MY_FILE as a parametric macro:

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

EDIT: As noted by "Lindydancer", this solution doesn't expand macros in arguments. A more general solution is:

#define MY_FILE_(x,y) "/home..." #x #y
#define MY_FILE(x,y) MY_FILE_(x,y)
Giuseppe Guerrini
  • 4,274
  • 17
  • 32
  • 1
    In my honest opinion, this is the best answer, and is much simpler than the other suggestions. I'm surprised it didn't get a better rating! – osirisgothra Oct 26 '13 at 10:56
  • 5
    It's a clean solution which, unfortunately, doesn't work. If the argument passed to `MY_FILE` are macros, say `A` and `B`, this macro will expand to `"/home..." "A" "B"`. – Lindydancer Sep 02 '14 at 06:14
0

You can do that with 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
  • 131,725
  • 17
  • 180
  • 271