Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 700
Vinz Avatar asked Sep 09 '16 02:09

Vinz


Video Answer


1 Answers

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.

like image 103
Jonathan Leffler Avatar answered Nov 05 '22 17:11

Jonathan Leffler