2015-05-07 21 views
9

Ho letto alcuni articoli su Unicode e mi sono reso conto che mi rimane ancora confuso cosa fare esattamente al riguardo.C++ string letterale ancora confuso

Come programmatore C++ su piattaforma Windows, le discipline che mi sono state date erano per lo più identiche a quelle di qualsiasi insegnante: utilizzare sempre il set di caratteri Unicode; templatizzarlo o utilizzare TCHAR se possibile; preferisco wchar_t, std :: wstring su 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 

In qualche modo ho incasinato, e mi portano a me stesso di credere che se io dico "qualcosa", che significa che è ASCII formattato, e se dico L "qualcosa" è Unicode. Poi ho letto questo:

tipo wchar_t è un tipo distinto i cui valori possono rappresentare codici distinti per tutti i membri del set di caratteri esteso più grande specificato tra le lingue supportate (22.3.1). Il tipo wchar_t deve avere le stesse dimensioni, firma e requisiti di allineamento (3.11) come uno degli altri tipi interi, chiamato il suo tipo sottostante. Tipi char16_t e char32_t indicano tipi distinti con le stesse dimensioni, signnessness e allineamento di uint_least16_t e uint_least32_t, rispettivamente, in, chiamati tipi sottostanti.

Quindi cosa? Se il mio locale dice iniziare dalla codepage 949, l'estensione di wchar_t è 949 + 2^(sizeof (wchar_t) * 8)? E il modo in cui parla sembra "Non mi interessa se la tua implementazione di C++ usa la codifica UTF o cosa".

Almeno, potrei capire che tutto dipende da quale locale è l'applicazione. Così ho provato:

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

Poi uscita era:

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 

Un'altra uscita con locale coreano:

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 

Un'altra uscita:

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 

Si scopre Se io non dare la giusta localizzazione, applicazione non riesce a gestire un certo numero di caratteri, non importa che abbia usato char o wchar_t. Questo non è solo un problema. Visual studio dà avvertimento:

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

Non sono sicuro se questo sta descrivendo quello che sto ottenendo come output o qualcos'altro.

Domanda. Quali sarebbero le migliori pratiche e perché? Come si può rendere una piattaforma applicativa/implementazione/nazione indipendente? cosa succede esattamente alle stringhe letterali sulla fonte? come vengono interpretati i valori stringa dall'applicazione?

+1

Per la massima compatibilità: mantenere i caratteri nella sorgente sui caratteri ASCII di base. Usa la codifica UTF8 usando i byte definiti con \ x nelle stringhe. Il nuovo file u8 "\ u1234" nell'ultima versione di C++ renderà tutto più semplice, ma non è ancora supportato da Visual Studio. Vedi anche questa domanda: http://stackoverflow.com/questions/3768363/character-sets-not-clear – JCx

+1

'' TCHAR's sono una seccatura gigantesca. A meno che tu non stia cercando di supportare versioni molto vecchie di Windows, dai solo alle stringhe di Windows. Per compatibilità con altre cose, è possibile memorizzare stringhe utilizzando UTF-8 e convertirle quando si utilizza una funzione API di Windows. – chris

risposta

3

C++ non ha il supporto Unicode normale. Non puoi semplicemente wirte normalmente un'applicazione globalizzata in C++ senza usare librerie di terze parti. Leggi this perspicace risposta SO. Se hai davvero bisogno di scrivere un'applicazione che usa Unicode, guarderei la libreria ICU.

2

Su Windows, Microsoft guarantees che wchar_t supporta Unicode, in modo L"핼로" è il modo corretto per produrre una stringa UTF-16 letterale come const wchar_t*.Su altre piattaforme, questo non è necessariamente valido, e dovresti usare le stringhe di stringa Unicode C++ 11 (u8"...", u"..." e U"...") se hai bisogno che il tuo codice sia portatile, per esempio, usa u8"핼로" per produrre un UTF-8 codificato const char* (come da Visual Studio 2015).

L'altro problema riscontrato è il modo in cui Visual Studio interpreta la codifica del file sorgente. Ad esempio,è codificato come 0xAA 0xAA in EUC-KR (codice pagina 949), che è la codifica per ªª nella code page 1252 (fr-FR), ovvero, se si è salvato il file sorgente contenente in EUC-KR ma compilalo in un locale fr-FR, il tuo letterale codificherà ªª.

Se è necessario includere caratteri non ASCII nell'origine, è necessario salvarli con un UTF (ad esempio, UTF-8/16/32) con un BOM esplicito, descritto in answer to this question.

+0

Hai ragione. Stavo per concludere che Microsoft convertirà il letterale stringa di caratteri wide (L "Something") in UCS-2 e qualsiasi cosa al di fuori di BMP li renderà pazzi. Tuttavia, il test aggiuntivo mi dice che sono interpretati correttamente come UTF-16 correttamente. Grazie. – user2883715

Problemi correlati