C Macros to create strings
Alternative Titles (to aid search)
- Convert a preprocessor token to a string
- How to make a char string from a C macro's value?
Original Question
I would like to use C #define
to build literal strings at compile time.
The string are domains that change for debug, release etc.
I would like to some some thing like this:
#ifdef __TESTING
#define IV_DOMAIN domain.org //in house testing
#elif __LIVE_TESTING
#define IV_DOMAIN test.domain.com //live testing servers
#else
#define IV_DOMAIN domain.com //production
#endif
// Sub-Domain
#define IV_SECURE "secure.IV_DOMAIN" //secure.domain.org etc
#define IV_MOBILE "m.IV_DOMAIN"
But the preprocessor doesn't evaluate anything within ""
- Is there a way around this?
- Is this even a good idea?
Solution 1:
In C, string literals are concatenated automatically. For example,
const char * s1 = "foo" "bar";
const char * s2 = "foobar";
s1
and s2
are the same string.
So, for your problem, the answer (without token pasting) is
#ifdef __TESTING
#define IV_DOMAIN "domain.org"
#elif __LIVE_TESTING
#define IV_DOMAIN "test.domain.com"
#else
#define IV_DOMAIN "domain.com"
#endif
#define IV_SECURE "secure." IV_DOMAIN
#define IV_MOBILE "m." IV_DOMAIN
Solution 2:
There are a couple ways to do this:
if you're dealing with only string literals, you can simply use simply use strings - placing one string literal after another causes the compiler to concatenate them.
if there may be other things than string literals involved (ie., you are creating new identifiers from the macros) use the '
##
" preprocessor token pasting operator. You'd probably also need to use the '#
' 'stringizing operator to make your macros into literal strings.
An example of #1:
#ifdef __TESTING
#define IV_DOMAIN "domain.org" //in house testing
#elif __LIVE_TESTING
#define IV_DOMAIN "test.domain.com" //live testing servers
#else
#define IV_DOMAIN "domain.com" //production
#endif
// Sub-Domain
#define IV_SECURE "secure." IV_DOMAIN //secure.domain.org etc
#define IV_MOBILE "m." IV_DOMAIN
And as far as the token pasting operator goes, I don't think that most of the answers that suggested using the token pasting preprocessor operator have actually tried it - it can be tricky to use.
Using the answer that is often suggested will result in a compiler error when you try to use the IV_SECURE
macro, because:
#define IV_SECURE "secure."##IV_DOMAIN
expands to:
"secure"domain.org
You might want to try to use the '
#`' 'stringizing' operator:
#define IV_SECURE "secure." #IV_DOMAIN
But that won't work because it only works on macro arguments - not just any old macro.
one thing to be aware of when you're using the token-paste ('##') or stringizing ('#') preprocessing operators is that you have to use an extra level of indirection for them to work properly in all cases.
If you don't do this and the items passed to the token-pasting operator are macros themselves, you'll get results that are probably not what you want:
#include <stdio.h>
#define STRINGIFY2( x) #x
#define STRINGIFY(x) STRINGIFY2(x)
#define PASTE2( a, b) a##b
#define PASTE( a, b) PASTE2( a, b)
#define BAD_PASTE(x,y) x##y
#define BAD_STRINGIFY(x) #x
#define SOME_MACRO function_name
int main()
{
printf( "buggy results:\n");
printf( "%s\n", STRINGIFY( BAD_PASTE( SOME_MACRO, __LINE__)));
printf( "%s\n", BAD_STRINGIFY( BAD_PASTE( SOME_MACRO, __LINE__)));
printf( "%s\n", BAD_STRINGIFY( PASTE( SOME_MACRO, __LINE__)));
printf( "\n" "desired result:\n");
printf( "%s\n", STRINGIFY( PASTE( SOME_MACRO, __LINE__)));
}
The output:
buggy results:
SOME_MACRO__LINE__
BAD_PASTE( SOME_MACRO, __LINE__)
PASTE( SOME_MACRO, __LINE__)
desired result:
function_name21
So using your original IV_DOMAIN
defines and the utilty macros from above, you could do this to get what you want:
// Sub-Domain
#define IV_SECURE "secure." STRINGIFY( IV_DOMAIN) //secure.domain.org etc
#define IV_MOBILE "m." STRINGIFY( IV_DOMAIN)