Search code examples
c++cmacrosc-preprocessorstringification

Stringify Macro with Unicode String Literal


I'm using this preprocessor macro to "stringify" and return easily from a definition resolving function:

#define STRINGIFY_RETURN(x) case x:     return #x ""

It works like a charm in MBSC environment with normal string literals. Example:

#define MY_DEFINE_1 1
#define MY_DEFINE_2 2
#define MY_DEFINE_3 3

const char* GetMyDefineNameA(unsigned int value)
{
    switch(value)
    {
        STRINGIFY_RETURN(MY_DEFINE_1);
        STRINGIFY_RETURN(MY_DEFINE_2);
        STRINGIFY_RETURN(MY_DEFINE_3);
        default:    return "Unknown";
    }
}

However I had to switch to Unicode compatibility more and more and so I had to rewrite this function to return Unicode strings which require the prefixing with L in front of the string literals. So I tried:

#define STRINGIFY_RETURN_WIDE(x)    case x:     return #x L""

const wchar_t* GetMyDefineNameW(unsigned int value)
{
    switch(value)
    {
        STRINGIFY_RETURN_WIDE(MY_DEFINE_1);
        STRINGIFY_RETURN_WIDE(MY_DEFINE_2);
        STRINGIFY_RETURN_WIDE(MY_DEFINE_3);
        default:    return L"Unknown";
    }
}

But that gives me the errors:

error C2308: concatenating mismatched strings

error C2440: 'return' : cannot convert from 'const char [12]' to 'const wchar_t *

I also tried:

#define STRINGIFY_RETURN_WIDE(x)    case x:     return L #x ""
#define STRINGIFY_RETURN_WIDE(x)    case x:     return #x "" L

but no matter what, I can't get it to work. I'm clueless about this and can't seem to find a solution.

I'd be really grateful if someone could show the correct way to do this macro so that it resolves to a Unicode string literal.

Update:

#define STRINGIFY_RETURN_WIDE(x)    case x:     return L#x ""

does not throw the C2440 error, but it still gives me the C2308.

Update 2:

I'm using Microsoft Visual Studio 2013


Solution

  • You have two main options:

    #define STRINGIFY_RETURN_WIDE(x) case x: return L#x L""
    

    This concatenates two L"…" strings. The alternative, and simpler, solution is to not concatenate the empty string:

    #define STRINGIFY_RETURN_WIDE(x) case x: return L#x
    

    It is not clear that there's any benefit to appending an empty string.


    As Robert Prévost noted in a comment, this does not work with G++ and Clang++, though it seems to work for Vinzenz with his compiler (Microsoft Visual Studio 2013).

    The problem is that the preprocessor tokenizes its input, and a wide string literal L"..." is all one token, but the macro above tries to generate tokens L and "..."`, leading to problems:

    xx11.cpp:5:49: error: ‘L’ was not declared in this scope
     #define STRINGIFY_RETURN_WIDE(x) case x: return L#x
                                                     ^
    xx11.cpp:11:9: note: in expansion of macro ‘STRINGIFY_RETURN_WIDE’
             STRINGIFY_RETURN_WIDE(MY_DEFINE_1);
    

    There is a workaround:

    #define MY_DEFINE_1 1
    #define MY_DEFINE_2 2
    #define MY_DEFINE_3 3
    
    #define LSTR(x) L ## x
    #define STRINGIFY_RETURN_WIDE(x) case x: return LSTR(#x)
    
    const wchar_t* GetMyDefineNameW(unsigned int value)
    {
        switch(value)
        {
            STRINGIFY_RETURN_WIDE(MY_DEFINE_1);
            STRINGIFY_RETURN_WIDE(MY_DEFINE_2);
            STRINGIFY_RETURN_WIDE(MY_DEFINE_3);
            default:    return L"Unknown";
        }
    }
    

    Checked on Mac OS X 10.11.6 with GCC 6.2.0.