2016-09-09 2 views
7

Я использую этот препроцессора макрос «stringify» и легко вернуться из функции разрешающего определения:Stringify Macro с Unicode строковый литерал

#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: 'возвращение': не удается преобразовать из «сопзЬ гольца [12] 'до' сопзЬ wchar_t *

Я также попытался:

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

но несмотря ни на что, я не могу заставить его работать. Я не знаю об этом и не могу найти решение.

Я был бы очень благодарен, если бы кто-то мог показать правильный способ сделать этот макрос, чтобы он разрешил строковый литерал в Юникоде.

Update:

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

не бросает ошибку C2440, но она по-прежнему дает мне C2308.

Update 2:

Я использую Microsoft Visual Studio 2013

+1

Вы должны распечатать предварительно обработанный файл, чтобы посмотреть, что именно производится компилятором, а затем работать оттуда. – PaulMcKenzie

+0

бы вы не просто хотите: #define STRINGIFY_RETURN_WIDE (х) Случай х: возвращение L # х «» –

+0

@TimBeaudet Я просто попытался, это дает мне C2308 как хорошо, но ошибка C2440 ушла:/ – Vinzenz

ответ

5

У вас есть два основных варианта:

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

Это Объединяет две L"…" строки. В качестве альтернативы, и проще, решение не сцепить пустую строку:

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

Это не ясно, что есть какие-либо выгоды для добавления пустой строки.


Как Robert Prévost отмечено в comment, это не работает с 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.

+0

Еще раз спасибо, что сработало. Могу ли я спросить, есть ли какая-либо возможная причина, по которой можно было бы конкатенировать пустую строку в этом макросе? Я видел это несколько раз, ища это. Оставляя пустые литералы компилируемыми, и я счастлив, это просто мое любопытство. – Vinzenz

+1

Это не работает для clang ++. Просто для полноты определения двух макросов. #define _T (x) L ## x #define STRINGIFY_RETURN_WIDE (x) case x: return _T (#x). –

+0

@ RobertPrévost: Это интригует; проблема связана с токенизацией и как L является или не обрабатывается как часть строки. Я подозреваю, что 'clang ++' принимает более строго правильное отношение к вещам, но это означает, что если вам нужно использовать строковый оператор '#' и префикс строкового типа, то вы застряли в технике с двумя макросами контур. Спасибо что подметил это. –

2

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 будет вашим желаемым результатом для широких символов.

Смежные вопросы