2015-09-07 10 views
7

Su linux con g ++, se imposto un locale globale utf8, quindi wcin transcodifica correttamente UTF-8 nella codifica interna wchar_t.wcin.imbue e UTF-8

Tuttavia, se utilizzo la versione locale classica e inserisco un'impostazione locale UTF8 in wcin, ciò non accade. L'input fallisce del tutto, o ogni singolo byte viene convertito in wchar_t indipendentemente.

Con clang ++ e libC++, non funzionano né le impostazioni internazionali globali né le impostazioni internazionali in wcin.

#include <iostream> 
#include <locale> 
#include <string> 

using namespace std; 

int main() { 
    if(true)   
     // this works with g++, but not with clang++/libc++ 
     locale::global(locale("C.UTF-8")); 
    else 
     // this doesn't work with either implementation 
     wcin.imbue(locale("C.UTF-8")); 
    wstring s; 
    wcin >> s; 
    cout << s.length() << " " << (s == L"áéú"); 
    return 0; 
} 

Il flusso di input contiene solo áéú caratteri. (Sono in UTF-8, non in una codifica a singolo byte).

Demo live: onetwo (Non riesco a riprodurre l'altro comportamento con i compilatori online).

È conforme allo standard? Non dovrei essere in grado di lasciare la sola impostazione globale e usare invece imbue?

Uno dei comportamenti descritti deve essere classificato come bug di implementazione?

+1

Cosa intendi con "clang ++" qui? Il compilatore è irrilevante poiché dipende interamente dalla libreria standard (entrambe le parti C e C++) e dai dati locali installati sulla macchina. Hai controllato sia con libstdC++ che con libC++, o semplicemente controllando libstdC++ due volte con due compilatori? –

+0

@JonathanWakely Hai ragione, avrei dovuto dire "libstdC++ e libC++". Penso di aver usato libC++ con clang ++ ma non riesco a verificarlo adesso. Ricontrollare e aggiornare non appena arrivo alla mia macchina. –

+0

OK, allora mi chiedo se il problema è una limitazione fondamentale di 'wcin', in quanto la conversione da ottetti UTF-8 a' wchar_t' viene eseguita dal livello stdio, che usa la locale globale non quella del flusso. Ma potrebbe essere solo un bug in libstdC++ (e forse anche in libC++), non ne sono sicuro. Anch'io mi aspetterei che il tuo uso di "imbusta" funzioni. –

risposta

2

Prima di tutto dovresti usare wcout con wcin.

Ora avete due possibili soluzioni a questo:

1) disattivare la sincronizzazione di iostream e flussi cstdio utilizzando

ios_base::sync_with_stdio(false); 

nota, che questa dovrebbe essere la prima chiamata, in caso contrario il comportamento dipende implementazione.

int main() { 

    ios_base::sync_with_stdio(false); 
    wcin.imbue(locale("C.UTF-8")); 

    wstring s; 
    wcin >> s; 
    wcout << s.length() << " " << (s == L"áéú"); 
    return 0; 
} 

2) Localizzare sia locale e wcout:

int main() { 

    std::setlocale(LC_ALL, "C.UTF-8"); 
    wcout.imbue(locale("C.UTF-8")); 

    wstring s; 
    wcin >> s; 
    wcout << s.length() << " " << (s == L"áéú"); 
    return 0; 
} 

Provato entrambi utilizzando Ideone, funziona bene. Non ho clang ++/libC++ con me, quindi non ero in grado di testare questo comportamento, mi dispiace.

+0

OK So che il setlocale globale funziona con libstdC++. Ma perché abbiamo bisogno di unsync con stdio per impregnare un locale? Non ho trovato nulla nello standard. –

+0

La sincronizzazione consente di utilizzare cout e printf nello stesso programma. Gli stream C non locali interromperanno la codifica utf-8 mentre sono sincronizzati con il flusso C++. Ecco perché la seconda soluzione utilizza il setlocale globale. –

+1

Ma non faccio alcun I/O del flusso C, perché è ancora necessario il unsync? –