2013-03-18 11 views
9

Odkryłem nową funkcjonalność Unicode w C++ 11, a podczas gdy other C++11 encoding questions były bardzo pomocne, mam pytanie dotyczące następującego fragmentu kodu z cppreference. Kod zapisuje, a następnie natychmiast odczytuje plik tekstowy zapisany z kodowaniem UTF-8.Czytanie/pisanie/drukowanie UTF-8 w C++ 11

// Write 
std::ofstream("text.txt") << u8"z\u6c34\U0001d10b"; 

// Read 
std::wifstream file1("text.txt"); 
file1.imbue(std::locale("en_US.UTF8")); 
std::cout << "Normal read from file (using default UTF-8/UTF-32 codecvt)\n"; 
for(wchar_t c; file1 >> c;) // ? 
    std::cout << std::hex << std::showbase << c << '\n'; 

Moje pytanie jest po prostu, dlaczego potrzebny jest wchar_t w pętli for? Literał łańcuchowy u8 można zadeklarować za pomocą prostego char *, a układ bitowy kodowania UTF-8 powinien informować system o szerokości znaku. Wygląda na to, że istnieje pewna automatyczna konwersja z UTF-8 na UTF-32 (stąd wchar_t), ale jeśli tak jest, dlaczego konwersja jest konieczna?

+0

To zależy od wielu rzeczy. Zauważalne, poprawne zachowanie UTF8 jest niezwykle trudne, jeśli nie niemożliwe, używając Windows w aplikacji konsolowej (wymagającej _a co najmniej_ dużej liczby niestandardowych wywołań API IIRC) – sehe

+1

'wchar_t' jest używany, ponieważ' wifstream' jest używany, a 'wifstream' wykonuje że "niektóre automatyczne konwersje" wspominasz. Chciałem pokazać różnicę między tą automatyczną konwersją (zaimplementowaną dla jednej konkretnej platformy) a jawną, przenośną, niezależną od ustawień lokalnych konwersją Unicode zapewnioną przez 'codecvt_utf8_utf16'. – Cubbi

Odpowiedz

5

Używasz wchar_t, ponieważ czytasz plik, używając wifstream; jeśli czytasz przy użyciu ifstream, używałbyś char i podobnie do char16_t i char32_t.

Zakładając (jako przykład robi), że wchar_t jest 32-bitowy, a rodzimy zestaw znaków, że stanowi to UTF-32 (UCS-4), to jest to najprostszy sposób, aby odczytać plik jako UTF-32; jest przedstawiony jako taki w przykładzie dla kontrastu do czytania pliku jako UTF-16. Bardziej przenośną metodą byłoby jawne użycie basic_ifstream<char32_t> i std::codecvt_utf8<char32_t>, ponieważ gwarantuje to konwersję ze strumienia wejściowego UTF-8 na elementy UTF-32.

+1

+1, Napisałem ten przykład i kontrast był tym, do czego zmierzałem. – Cubbi

+0

Ah Widzę! Czy zatem lepiej jest zawsze jawnie konwertować kodowanie UTF-8 na szerszy "wchar_t", czy też można zaakceptować tylko wypakowanie surowych bajtów UTF-8 do natywnej tablicy "char" za pomocą 'ifstream'? Nie jestem pewien, czy wywnioskować z przykładu @ Cubbi, że ta druga jest złą praktyką, czy jest poza zakresem tego przykładu. – Ephemera

+0

@PLPiper tak zawsze możesz odczytać, co multibajt kodujący plik ma w tablicy znaków, bez angażowania żadnej z konwersji. Nie można wiele zrobić z taką tablicą w standardowym C++ (innym niż konwersja na szeroki pierwszy), ale wiele bibliotek pobiera dane wejściowe utf8. – Cubbi

2

Idea użytego fragmentu kodu cppreference służy do pokazania, jak odczytywać plik UTF-8 w łańcuchu znaków UTF-16, dlatego piszą go za pomocą strumienia, ale czytają go przy użyciu strumienia (stąd wchar_t) .