Ошибка Unixode С++ для потока
В настоящее время я пишу приложение, которое требует, чтобы я вызывал 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.
Извините за плохо построенный пост, я разрываю свои волосы здесь.
Спасибо.
EDIT:
Минимальный тестовый пример
#include <fstream>
#include <iostream>
int main()
{
{
std::wofstream test_file("test.txt");
test_file << L"\u2122";
}
std::wcout << L"\u2122";
}
Ожидаемый результат: символ "™" печатается на консоль и файл.
Наблюдаемый результат: Файл создан, но пуст. Нет вывода на консоль.
Я подтвердил, что шрифт, который я использую для моей консоли, способен отображать соответствующий символ, и файл определенно пуст (размером 0 байт).
EDIT:
Дальнейшая отладка показывает, что в потоке (потоках) установлены "failbit" и "badbit".
EDIT:
Я также пробовал использовать Boost.Locale, и у меня такая же проблема, даже с новой локалью, внедренной глобально и явно во все стандартные потоки.
Ответы
Ответ 1
Чтобы записать в файл, вы должны установить локаль правильно, например, если вы хотите записать их как символы 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";
}
Ответ 2
Вы всегда используете std::wcout
или иногда используете std::cout
? Смешивание их не будет работать. Конечно, описание ошибки "удушье" вообще не говорит о том, какую проблему вы наблюдаете. Я подозреваю, что это другая проблема для тех, кто использует файлы.
Поскольку нет реального описания проблемы, требуется немного хрустального шара, а затем выстрел в темноте, чтобы попасть в проблему... Поскольку вы хотите получить символы Unicode из вашего файла, убедитесь, что поток файлов вы использует a std::locale
, фасет std::codecvt<...>
фактически преобразуется в подходящую кодировку Unicode.
Ответ 3
Я только что протестировал GCC (версии 4.4 по 4.7) и MSVC 10, которые все проявляют эту проблему.
Равно сломанным является wprintf
, что делает как можно меньше API потока С++.
Я также проверил необработанный API Win32, чтобы увидеть, не вызвало ли что-либо другое отказ, и это работает:
#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
ужасно нарушен в больших реализациях стандартной библиотеки С++.
Ответ 4
Хотя широкие потоки символов принимают Unicode в качестве входных данных, это не то, что они производят в качестве вывода - символы проходят через преобразование. Если символ не может быть представлен в кодировке, в которую он преобразуется, выход не работает.