2016-09-09 35 views
7

używam tego makra preprocesora do „stringify” i wrócić łatwo z funkcją rozdzielczą definicji:stringify Makro z Unicode String Dosłowne

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

To działa jak czar w środowisku MBSC z normalnymi napisowych. Przykład:

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

Jednak musiałem przełączyć się do kompatybilności Unicode coraz więcej i tak musiałem przepisać tej funkcji, aby wrócić ciągi Unicode, które wymagają poprzedzanie z L z przodu napisowych. Tak próbowałem:

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

Ale to daje mi błędy:

error C2308: Połączenie niedopasowane strings

error C2440: 'return': nie można przekonwertować z „const char [12] 'do' const wchar_t *

próbowałem również:

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

ale nie ważne co, nie mogę go uruchomić. Nie mam pojęcia o tym i nie mogę znaleźć rozwiązania.

Byłbym naprawdę wdzięczny, gdyby ktoś mógł pokazać prawidłowy sposób wykonania tego makra, aby mógł zostać rozwiązany na literał ciągu znaków Unicode.

Aktualizacja:

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

nie rzucać się błąd C2440, ale wciąż daje mi C2308.

Aktualizacja 2:

Używam Microsoft Visual Studio 2013

+1

Powinieneś wydrukować wstępnie przetworzony plik, aby zobaczyć dokładnie, co wyprodukował kompilator, a następnie pracować z tego miejsca. – PaulMcKenzie

+0

Czy nie chcesz po prostu: #define STRINGIFY_RETURN_WIDE (x) x przypadek: powrót l # x „” –

+0

@TimBeaudet Właśnie próbował, to daje mi C2308 oraz C2440 ale błąd nie ma:/ – Vinzenz

Odpowiedz

5

Masz dwie główne opcje:

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

ten łączy dwa L"…" sznurki. Alternatywą i prostsze rozwiązanie jest nie łączyć pusty łańcuch:

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

Nie jest jasne, że nie ma żadnych korzyści dodanie pusty ciąg.


Jak Robert Prévost zauważyć w comment, to nie działa z G ++ i Clang ++, choć wydaje się pracować dla Vinzenz z jego kompilatora (Microsoft Visual Studio 2013).

Problemem jest to, że preprocesor tokenizes swoje wejście, a także szeroki ciąg dosłowne L"..." to wszystko jeden żeton, ale makro powyżej próbach do generowania tokenów L i „...” `, co prowadzi do problemów:

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

Istnieje obejście:

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

sprawdzone na Mac OS X 10.11.6 GCC 6.2.0.

+0

Jeszcze raz dziękuję, działało. Czy mogę zapytać, czy istnieje jakiś powód, dla którego można by połączyć pusty ciąg w tym makrze? Widziałem to kilka razy podczas poszukiwania tego. Pozostawienie pustych literałów kompiluje się i jestem szczęśliwy, to tylko moja ciekawość. – Vinzenz

+1

To nie działało dla języka ++. Tylko dla kompletności definiujemy dwa makra. #define _T (x) L ## x #define STRINGIFY_RETURN_WIDE (x) case x: return _T (#x). –

+0

@ RobertPrévost: To intrygujące; problem związany jest z tokenizacją i tym, jak L jest lub nie jest traktowane jako część ciągu. Podejrzewam, że 'clang ++' bierze bardziej bezwzględnie poprawny vie na rzeczy, ale to znaczy, że jeśli potrzebujesz użyć stringify operatora '# 'i prefiksu typu string, to utkniesz w technice dual-macro zarys. Dziękuję za wskazanie tego. –

2

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

Pokazuje, że:

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

Ponieważ ekspansja zawiera cytaty, myślę, że po prostu wrócić L # x byłby pożądanym wynikiem dla szerokich postaci.