Ошибка вывода потока Windows Unicode C++
В настоящее время я пишу приложение, которое требует от меня вызова GetWindowText в произвольных окнах и сохранения этих данных в файл для последующей обработки. Короче говоря, я заметил, что мой инструмент не работал в Battlefield 3, и я сузил проблему до следующего символа в заголовке окна: http://www.fileformat.info/info/unicode/char/2122/index.htm
Поэтому я создал небольшое тестовое приложение, которое просто делает следующее:
std::wcout << L"\u2122";
Низкий и вот, что прерывает вывод в окно консоли для остальной части программы.
Почему MSVC STL задыхается от этого символа (и я предполагаю, что другие), когда такие API, как MessageBoxW и т. Д., Отображают его просто отлично?
Как я могу распечатать эти символы в моем файле?
Протестировано на VC10 и VC11 под Windows 7 x64.
Извините за плохо построенный пост, я рву свои волосы здесь.
Благодарю.
РЕДАКТИРОВАТЬ:
Минимальный контрольный пример
#include <fstream>
#include <iostream>
int main()
{
{
std::wofstream test_file("test.txt");
test_file << L"\u2122";
}
std::wcout << L"\u2122";
}
Ожидаемый результат: символ "™" напечатан на консоли и в файле. Наблюдаемый результат: файл создан, но пуст. Нет вывода на консоль.
Я подтвердил, что шрифт, который я использую для своей консоли, способен отображать соответствующий символ, и файл определенно пуст (размером 0 байт).
РЕДАКТИРОВАТЬ:
Дальнейшая отладка показывает, что 'failbit' и 'badbit' установлены в потоке (ах).
РЕДАКТИРОВАТЬ:
Я также пытался использовать Boost.Locale, и у меня возникла та же проблема, даже с новой локалью, распространенной глобально и явно для всех стандартных потоков.
4 ответа
Чтобы записать в файл, вы должны правильно задать локаль, например, если вы хотите записать их как символы UTF-8, вы должны добавить
const std::locale utf8_locale
= std::locale(std::locale(), new std::codecvt_utf8<wchar_t>());
test_file.imbue(utf8_locale);
Вы должны добавить эти 2 включаемых файла
#include <codecvt>
#include <locale>
Для записи в консоль вы должны установить консоль в правильном режиме (это зависит от Windows), добавив
_setmode(_fileno(stdout), _O_U8TEXT);
(если вы хотите использовать UTF-8).
Для этого вы должны добавить эти 2 включаемых файла:
#include <fcntl.h>
#include <io.h>
Кроме того, вы должны убедиться, что вы используете шрифт, который поддерживает Unicode (например, Lucida Console). Вы можете изменить шрифт в свойствах вашего окна консоли.
Полная программа теперь выглядит так:
#include <fstream>
#include <iostream>
#include <codecvt>
#include <locale>
#include <fcntl.h>
#include <io.h>
int main()
{
const std::locale utf8_locale = std::locale(std::locale(),
new std::codecvt_utf8<wchar_t>());
{
std::wofstream test_file("c:\\temp\\test.txt");
test_file.imbue(utf8_locale);
test_file << L"\u2122";
}
_setmode(_fileno(stdout), _O_U8TEXT);
std::wcout << L"\u2122";
}
Вы всегда используете std::wcout
или вы иногда используете std::cout
? Смешивать их не получится. Конечно, в описании ошибки "удушье" вообще не сказано, какую проблему вы наблюдаете. Я подозреваю, что это проблема, отличная от той, которая использует файлы.
Поскольку нет реального описания проблемы, для решения проблемы требуется хрустальный шар с последующим выстрелом в темноте... Поскольку вы хотите получить символы Unicode из файла, убедитесь, что используемый вами файловый поток использует std::locale
чья std::codecvt<...>
Фасет фактически конвертируется в подходящую кодировку Unicode.
Я только что протестировал GCC (версии 4.4 - 4.7) и MSVC 10, которые все демонстрируют эту проблему.
В равной степени нарушается wprintf
, который делает так же мало, как потоковый API C++.
Я также протестировал сырой Win32 API, чтобы убедиться, что больше ничего не было причиной сбоя, и это работает:
#include <windows.h>
int main()
{
HANDLE stdout = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD n;
WriteConsoleW( stdout, L"\u03B2", 1, &n, NULL );
}
Который пишет β
на консоль (если вы установили шрифт cmd на что-то вроде Lucida Console).
Заключение: wchar_t
выходные данные ужасно искажены в обеих больших реализациях стандартной библиотеки C++.
Хотя широкие символьные потоки принимают Unicode в качестве входных данных, это не то, что они создают в качестве выходных данных - символы проходят преобразование. Если символ не может быть представлен в кодировке, в которую он конвертируется, вывод завершается неудачно.