使用Unicode字符串文字对宏进行Stringify

Stringify Macro with Unicode String Literal

本文关键字:Stringify Unicode 字符串 文字 使用      更新时间:2023-10-16

我使用这个预处理器宏来"stringify"并轻松地从定义解析函数返回:

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

在具有正常字符串字面值的MBSC环境中,它像一个魅力一样工作。例子:

#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";
    }
}

然而,我不得不越来越多地切换到Unicode兼容性,所以我不得不重写这个函数来返回Unicode字符串,这需要在字符串字面量前面加上L的前缀。所以我试了:

#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";
    }
}

但是这给了我错误:

错误C2308:连接不匹配字符串

错误C2440: 'return':无法从'const char[12]'转换为'const wchar_t * '

我也试过:

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

但无论如何,我不能让它工作。我对此毫无头绪,似乎找不到解决办法。

我真的很感激如果有人可以显示正确的方法来做这个宏,使它解析为Unicode字符串字面值。

更新:

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

不抛出C2440错误,但它仍然给我C2308。

更新2:

我使用的是Microsoft Visual Studio 2013

你有两个主要的选择:

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

连接两个L"…"字符串。另一种更简单的解决方案是不连接空字符串:

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

附加一个空字符串是否有任何好处还不清楚。


正如Robert pracimvost在评论中指出的,这在g++和clang++中不起作用,虽然它似乎对Vinzenz和他的编译器(Microsoft Visual Studio 2013)有效。

问题在于预处理器对其输入进行了标记,并且宽字符串字面值L"..."都是一个标记,但是上面的宏试图生成标记L和"…"' ',导致问题:

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

有一个解决方法:

#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";
    }
}

在Mac OS X 10.11.6和GCC 6.2.0上检查

http://en.cppreference.com/w/cpp/preprocessor/replace

显示:

#define showlist(...) puts(#__VA_ARGS__)
showlist();            // expands to puts("")
showlist(1, "x", int); // expands to puts("1, "x", int")

由于展开包括引号,我认为简单地返回l# x将是您对宽字符的期望结果。