C++: неправильно выводятся широкие символы?

Мой код в основном таков:

wstring japan = L"日本";
wstring message = L"Welcome! Japan is ";

message += japan;

wprintf(message.c_str());

Я хочу использовать широкие строки, но не знаю, как они выводятся, поэтому я использовал wprintf. Когда я запускаю что-то вроде:

./widestr | hexdump

Шестнадцатеричные кодовые точки создают это:

65 57 63 6c 6d 6f 21 65 4a 20 70 61 6e 61 69 20 20 73 3f 3f
e  W  c  l  m  o  !  e  J     p  a  n  a  i        s  ?  ?

Почему они все прыгают по порядку? Я имею в виду, что если wprintf неверен, я все еще не понимаю, почему он выводится в таком специфическом перемешанном порядке!

редактировать: endianness или что-то в этом роде? они, кажется, меняют каждые два символа. хм.

РЕДАКТИРОВАТЬ 2: я пытался использовать wcout, но он выводит те же самые шестнадцатеричные кодовые точки. Странный!


person John D.    schedule 28.06.2010    source источник
comment
Может быть, вам стоит попробовать cout << message << endl.   -  person phimuemue    schedule 28.06.2010
comment
@phimuemue, это не работает, оно отправляет мне примерно 30 ошибок, первая из которых widestr.cpp:18: error: no match for ‘operator<<’ in ‘std::cout << message‘, в том числе многие о признаках ostream char или что-то в этом роде. Он не выводит широкую строку!   -  person John D.    schedule 28.06.2010
comment
Какую платформу и компилятор вы используете?   -  person hlovdal    schedule 28.06.2010
comment
Я на GCC/Linux 2.6 (x86).   -  person John D.    schedule 29.06.2010


Ответы (1)


Вам нужно определить локаль

    #include <stdio.h>
    #include <string>
    #include <locale>
    #include <iostream>

    using namespace std;

    int main()
    {

            std::locale::global(std::locale(""));
            wstring japan = L"日本";
            wstring message = L"Welcome! Japan is ";

            message += japan;

            wprintf(message.c_str());
            wcout << message << endl;
    }

Работает так, как ожидалось (т.е. преобразует широкую строку в узкую UTF-8 и печатает ее).

Когда вы определяете глобальную локаль как "" - вы устанавливаете системную локаль (и если это UTF-8, она будет распечатана как UTF-8 - т.е. будет преобразована wstring)

Редактировать: забудьте, что я сказал о sync_with_stdio — это неверно, они синхронизированы по умолчанию. Не нужно.

person Artyom    schedule 28.06.2010
comment
Вы говорите, что sync_with_stdio и wcout - альтернативы; они делают совершенно разные вещи. sync_with_stdio требуется, если вы хотите чередовать потоковые функции C (например, wprintf) с использованием потока C++ (wcout); imbue необходим, если вы хотите изменить локаль, используемую wcout. - person CB Bailey; 28.06.2010
comment
Я не могу это проверить, но wcout должен работать без настроек кодовой страницы в Windows, потому что wchar_t — это кодовая единица UTF-16 в Windows, а UTF-16 — единственная родная кодировка Windows. Таким образом, std::wcout должен использовать WriteConsoleW без преобразования локали. Если это не так, это ошибка библиотеки. - person Philipp; 28.06.2010
comment
@Philipp Это не то, как это определяется стандартом. Стандарт говорит, что широкие символы должны быть преобразованы в узкую кодировку в соответствии с кодовой страницей локали. И это то, что делается. Проблема с Windows в том, что она не поддерживает UTF-8. Так что для Windows вам, вероятно, нужно использовать locale::globale(locale("Japan")), и на выходе будет использоваться кодировка Shift-JIS. В противном случае он не сможет преобразовать символы. - person Artyom; 28.06.2010
comment
Реализация стандартных библиотек Microsoft wcout использует глобальную c-locale внутри, поэтому наполнение локали практически бесполезно. Вы должны установить желаемую локаль в качестве глобальной локали... - person smerlin; 28.06.2010
comment
@Artyom: Спасибо за комментарий. Это означает, что std::wcout практически бесполезен в Windows. Я бы посчитал это ошибкой в ​​стандарте C++, который излишне предвзято относится к Unix. Кстати, консоли Windows поддерживают UTF-8 (через SetConsoleCodePage), но все кодовые страницы устарели и сохраняются только из соображений совместимости. Shift-JIS еще более устарел, чем UTF-8, потому что это не кодировка Unicode. Так что кажется, что действительно нужно вызывать WriteConsoleW напрямую. - person Philipp; 28.06.2010
comment
относительно моего комментария: это верно только для аспекта ctype, наполнение локали работает для всех других аспектов AFAIK - person smerlin; 28.06.2010
comment
@Artyom, , @другие спасибо, это помогло мне выучить раздражающую часть языка. Теперь работает нормально. - person John D.; 28.06.2010
comment
вывод wprintf соответствует ожиданиям, но wcout не показывает никакого вывода (все пустые). почему так? - person parasrish; 15.12.2015
comment
Как насчет японских символов, таких как L{\type\:\string\,\value\:\\鳥\},\n . Похоже, это не wprintf или wcout, как показано выше. - person Michele; 10.04.2017