2015-05-07 9 views
9

Ich habe einige Artikel über Unicode Lesen und erkannte ich bin verwirrt noch übrig, was dagegen zu tun genau.C++ String noch wörtlichen verwirrend

als C++ Programmierer auf Windows-Plattform, die ich gegeben Disziplinen waren von jedem Lehrer meist gleich: immer Unicode-Zeichensatz verwenden; templatisieren Sie es oder verwenden Sie TCHAR wenn möglich; bevorzuge wchar_t, std :: wstring über char, std :: string.

#include <tchar.h> 
#include <string> 
typedef std::basic_string<TCHAR> tstring; 
// ... 
static const char* const s_hello = "핼로"; // bad 
static const wchar_t* const s_wchar_hello = L"핼로" // better 
static LPCTSTR s_tchar_hello = TEXT("핼로") // even better 
static const tstring s_tstring_hello(TEXT("핼로")); // best 

Irgendwie verwirrt ich, und ich führen mich zu glauben, dass, wenn ich „etwas“ sagen, dass es im ASCII-Format bedeutet, und wenn ich L „etwas“ sagen ist es Unicode. Dann lese ich das:

Typ wchar_t ist ein unterschiedlicher Typ, dessen Werte unterschiedliche Codes für alle Mitglieder des größten erweiterten Zeichensatzes, der unter den unterstützten Gebietsschemata (22.3.1) angegeben ist, darstellen können. Typ wchar_t muss die gleiche Größe, Signedness und Alignment-Anforderungen (3.11) wie einer der anderen ganzzahligen Typen haben, der so genannte zugrunde liegende Typ. Typen char16_t und char32_t verschiedene Arten mit der gleichen Größe, Signedness und Ausrichtung wie uint_least16_t und uint_least32_t bezeichnen jeweils, an, um die zugrunde liegenden Typen genannt.

So what? Wenn mein Gebietsschema von der Codepage 949 aus beginnt, ist die Ausdehnung von wchar_t von 949 + 2^(sizeof (wchar_t) * 8)? Und die Art, wie es spricht, klingt wie "Es ist mir egal, ob Ihre Implementierung von C++ UTF-Kodierung verwendet oder was".

Zumindest konnte ich verstehen, dass alles davon abhängt, auf welchem ​​Gebietsschema die Anwendung läuft. So testete ich:

#define TEST_OSTREAM_PRINT(x) \ 
std::cout << "----" << std::endl; \ 
std::cout << "cout : " << x << std::endl; \ 
std::wcout << "wcout : " << L##x << std::endl; 

int main() 
{ 
    std::ostream& os = std::cout; 

    std::cout << " * Info : " << std::endl 
       << "  sizeof(char) : " << sizeof(char) << std::endl 
       << "  sizeof(wchar_t) : " << sizeof(wchar_t) << std::endl 
       << "  littel endian? : " << IsLittelEndian() << std::endl; 
    std::cout << " - LC_ALL: " << setlocale(LC_ALL, NULL) << std::endl; 
    std::cout << " - LC_CTYPE: " << setlocale(LC_CTYPE, NULL) << std::endl; 

    TEST_OSTREAM_PRINT("핼로"); 
    TEST_OSTREAM_PRINT("おはよう。"); 
    TEST_OSTREAM_PRINT("你好"); 
    TEST_OSTREAM_PRINT("resume"); 
    TEST_OSTREAM_PRINT("résumé"); 

    return 0; 
} 

Dann Ausgang war:

Info 
sizeof(char) = 1 
sizeof(wchar_t) = 2 
LC_ALL = C 
LC_CTYPE = C 
---- 
cout : 핼로 
wcout : ---- 
cout : おはよう。 
wcout : ---- 
cout : ?好 
wcout : ---- 
cout : resume 
wcout : resume 
---- 
cout : r?sum? 
wcout : r?um 

Ein anderer Ausgang mit koreanischen locale:

Info 
sizeof(char) = 1 
sizeof(wchar_t) = 2 
LC_ALL = Korean_Korea.949 
LC_CTYPE = Korean_Korea.949 
---- 
cout : 핼로 
wcout : 핼로 
---- 
cout : おはよう。 
wcout : おはよう。 
---- 
cout : ?好 
wcout : ---- 
cout : resume 
wcout : resume 
---- 
cout : r?sum? 
wcout : resume 

Ein anderer Ausgang:

Info 
sizeof(char) = 1 
sizeof(wchar_t) = 2 
LC_ALL = fr-FR 
LC_CTYPE = fr-FR 
---- 
cout : CU·I 
wcout : ---- 
cout : ªªªIªeª|¡£ 
wcout : ---- 
cout : ?u¿ 
wcout : ---- 
cout : resume 
wcout : resume 
---- 
cout : r?sum? 
wcout : resume 

Es stellt sich heraus, wenn ich Geben Sie nicht das richtige Gebietsschema, Anwendung kann bestimmte Zeichenbereiche nicht verarbeiten, egal, ob ich char oder wchar_t verwendet habe. Das ist nicht nur ein Problem. Visual Studio gibt Warnung:

warning C4566: character represented by universal-character-name '\u4F60' cannot be represented in the current code page (949) 

Ich bin nicht sicher, ob dies beschreibt, was ich als Ausgabe oder etwas anderes bekomme.

Frage. Was wären die besten Praktiken und warum? Wie kann man eine Anwendungsplattform/Implementierung/Nation unabhängig machen? Was genau passiert mit String-Literalen auf der Quelle? Wie werden String-Werte von der Anwendung interpretiert?

+1

Für maximale Kompatibilität: Halten Sie die Zeichen in Ihrer Quelle zu den sehr einfachen ASCII-Zeichen. Verwenden Sie die UTF8-Codierung mit Bytes, die mit \ x in Strings definiert sind. Der neue u8 "\ u1234" Kram in der neuesten Version von C++ wird dies vereinfachen, aber es wird noch nicht von Visual Studio unterstützt. Siehe auch diese Frage: http://stackoverflow.com/questions/3768363/character-sets-not-clear – JCx

+1

'TCHAR' s sind eine gigantische Hektik. Wenn Sie nicht wirklich alte Windows-Versionen unterstützen möchten, geben Sie Windows-Strings einfach weiter. Um Kompatibilität mit anderen Dingen zu gewährleisten, können Sie Zeichenketten mit UTF-8 speichern und bei Verwendung einer Windows-API-Funktion konvertieren. – chris

Antwort

3

C++ hat keine normale Unicode-Unterstützung. Sie können normalerweise keine globalisierte Anwendung in C++ verwenden, ohne Bibliotheken von Drittanbietern zu verwenden. Lesen Sie this aufschlussreich SO Antwort. Wenn Sie wirklich eine Anwendung schreiben müssen, die Unicode verwendet, würde ich ICU Bibliothek betrachten.

2

Auf Windows, Microsoft guarantees dass wchar_t Unicode unterstützt, so L"핼로" ist der richtige Weg, um einen UTF-16 Stringliteral als const wchar_t* zu erzeugen.Auf anderen Plattformen gilt dies nicht unbedingt, und Sie sollten die C++ 11-Unicode-Zeichenfolgenliterale (u8"...", u"..." und U"...") verwenden, wenn Sie Ihren Code portabel haben möchten, z. B. u8"핼로", um ein UTF-8 zu erstellen codiert const char* (ab Visual Studio 2015).

Das andere Problem, auf das Sie stoßen, ist, wie Visual Studio die Codierung Ihrer Quelldatei interpretiert. Beispiel: ist codiert als 0xAA 0xAA in EUC-KR (Codepage 949). Dies ist die Codierung für ªª in Codepage 1252 (fr-FR), dh wenn Sie Ihre Quelldatei mit in EUC-KR gespeichert haben kompilieren Sie es in einem FR-FR-Gebietsschema, wird Ihr Literal ªª kodieren.

Wenn Sie Nicht-ASCII-Zeichen in Ihre Quelle einfügen müssen, sollten Sie sie in einem UTF (d. H. UTF-8/16/32) mit einer expliziten BOM speichern, die in answer to this question beschrieben ist.

+0

Sie haben Recht. Ich war im Begriff zu schlussfolgern, dass Microsoft ein breites Zeichenkettenliteral (L "Something") in UCS-2 umwandeln wird, und alles außerhalb von BMP macht sie verrückt. Ein zusätzlicher Test sagt mir jedoch, dass sie tatsächlich als UTF-16 interpretiert werden. Vielen Dank. – user2883715