std::wstring, std::wcout

Feb 16, 2008 20:54

Итак, std::wstring нужен только для корректного разбиения строки в многобайтной кодировке на символы. Для вывода таких строк не подходят стандартные потоки. Но в пространстве имен std определены и потоки для работы с "широкими" строками, например, std::wcout.
Вчера наткнулся на 2 особенности работы этих потоков.
Так, например, следующий код будет работать некорректно:

locale::global(locale(""));
cout << "abc" << endl;
wcout << "Привет" << endl;

Даже если локаль выставлена правильно, на выходе вместо "Привет" будут кракозябры. Это связанно с тем, что нельзя смешивать вывод "широких" и обычных символов в один поток. Если уж действительно сильно нужно - можно поставить в начале программы такой оператор:

ios::sync_with_stdio(false);

Это не баг компилятора (GCC). Это фича. Вот что они (разработчики GCC) пишут в рассылке:

"
This is a (new) feature, not a bug, see libstdc++/11705 and in general search
about stream orientation in the C standard (C99, 7.19.2). In a nutshell you
cannot mix byte oriented and wide oriented I/O. For now, due to the *bug*
pointed out in libstdc++/11705, you can obtain something close to your
expectations by calling std::ios::sync_with_stdio(false); at the beginning of
your program."

Вторая особенность связана с установкой локалей для потока (и глобально тоже). Рассмотрим код, приведенный на багреккере GCC:

wcout << 1 << endl;
locale::global(locale("en_US.UTF-8"));
wcout << L"\xF8" << endl;

По идее, этот код должен вывести 1 в первой строке и "LATIN SMALL LETTER O WITH A STROKE" во второй. Однако, этого не происходит. Похоже, что создание и инициализация потока происходит в момент его первого использования. И последующее изменение локали на него не влияет. Так, если убрать первую строчку в коде - он станет рабоать нормально.

wstring, gcc, locale, wcout, unicode

Previous post Next post
Up