28

I have a preprocessor macro defined in build settings

FOO=BAR

That value I want to massage into an Objective-C string literal that can be passed to a method. The following #define does not work, but it should demonstrate what I am trying to achieve:

 #define FOOLITERAL @"FOO" //want FOOLITERAL to have the value of @"BAR"

 myMethodThatTakesAnNSString(FOOLITERAL);

I expect that I am just missing the obvious somehow, but I cannot seem to find the right preprocessor voodoo to get what I need.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
vagrant
  • 868
  • 1
  • 9
  • 23

5 Answers5

36

Use the stringizing operator # to make a C string out of the symbol. However, due to a quirk of the preprocessor, you need to use two extra layers of macros:

#define FOO BAR
#define STRINGIZE(x) #x
#define STRINGIZE2(x) STRINGIZE(x)
#define FOOLITERAL @ STRINGIZE2(FOO)
// FOOLITERAL now expands to @"BAR" 

The reason for the extra layers is that the stringizing operator can only be used on the arguments of the macro, not on other tokens. Secondly, if an argument of a macro has the stringizing operator applied to it in the body of the macro, then that argument is not expanded as another macro. So, to ensure that FOO gets expanded, we wrap in another macro, so that when STRINGIZE2 gets expanded, it also expands FOO because the stringizing operator does not appear in that macro's body.

Adam Rosenfield
  • 390,455
  • 97
  • 512
  • 589
  • That did it. I had tried the double indirection, but also had the "@" as a macro value and that seems to confuse it. One small difference is that the first line does not represent my case in that it does not retrieve the build setting #define FOOVAL FOO #define STRINGIZE(x) #x #define STRINGIZE2(x) STRINGIZE(x) #define FOOLITERAL @ STRINGIZE2(FOOVAL) is what actually works for me. But your answer got me there. – vagrant Sep 30 '11 at 04:32
  • Hi @vagrant. Does this solution still work for you with LLVM? I'm trying to get this to work, but the actual value of FOO as defined in my build settings preprocessor macros never shows up. Could you maybe update your question with the solution that works for you? Cheers. – epologee Jul 29 '13 at 11:44
  • 1
    Why not just `#define Helper(STR) @ #STR` ? – tadeuzagallo Oct 15 '13 at 19:40
  • 1
    This is correct, but @Noa's answer below is much easier to use IMHO – Adam Feb 10 '14 at 22:52
  • Doesn't seem to work if FOO has commas in its value – Albert Renshaw Nov 24 '21 at 06:14
29

Here's a modified version of Adam Rosenfield's answer with clearer semantics:

#define NSStringize_helper(x) #x
#define NSStringize(x) @NSStringize_helper(x)

I use it to replace code like this:

case OneEnumValue: name = @"OneEnumValue"; break;
case AnotherEnumValue: name = @"AnotherEnumValue"; break;

with this:

#define case_for_type(type) case type: name = NSStringize(type); break

case_for_type(OneEnumValue);
case_for_type(AnotherEnumValue);
paulmelnikow
  • 16,895
  • 8
  • 63
  • 114
3

A convenient macro OS_STRINGIFY(s) is predefined in SDK's /usr/include/os/base.h, which is included in Foundation.framework.

So you can use the following code without additional definitions.

myMethodThatTakesAnNSString(@OS_STRINGIFY(FOO));
manicmaniac
  • 161
  • 1
  • 5
  • Great find. Essentially the solution of the accepted answer, but can be used consistently, without cluttering up application code with something that already exists in Apple's frameworks: https://opensource.apple.com/source/xnu/xnu-4903.241.1/libkern/os/base.h.auto.html – Nate Oct 30 '21 at 10:49
0

You need to define preprocessor macro like,

FOO=\@\"BAR\"

And use code side like,

[NSString stringWithFormat:@"macro: %@", FOO];
Sazzad Hissain Khan
  • 37,929
  • 33
  • 189
  • 256
-2

What error are you seeing exactly? This type of thing does work as you expect:

#define kMyString @"MyString"

[NSString stringWithFormat:@"macro: %@", kMyString];
D.C.
  • 15,340
  • 19
  • 71
  • 102
  • 3
    The actual value of the string needed is the value of the preprocessor macro. So I can't just put the value into the code like in your example, it has to come from the FOO variable. – vagrant Sep 30 '11 at 04:16