Я решил написать простой пример:
#include <iostream>
int main()
{
std::cout << u8"это строка6" << std::endl;
return 0;
}
Выполнил в консоли следующую команду:
ЧКП 65001
Выход программы:
��то строка6
Почему первый символ отображается неправильно? Я думаю, что кодовая страница 65001 использует спецификацию и считывает первый символ как спецификацию. Это правда?
Ну, вся стандартная библиотека ввода-вывода хитрая с этой кодовой страницей. Вот еще одна тестовая программа (\xe2\x86\x92
это стрелка →
в UTF-8):
#include <stdio.h>
int main(void)
{
char s[] = "\xe2\x86\x92 a \xe2\x86\x92 b\n";
int l = (int) sizeof(s) - 1;
int wr = fwrite(s, 1, l, stdout);
printf("%d/%d written\n", wr, l);
return 0;
}
И его вывод:
��� a → b
10/12 written
Обратите внимание, что первый символ снова заменяется ���
(это 3 байта в UTF-8), а fwrite
вызов возвращает номер персонажи написано на консоли. Это нарушение стандарта C (должно возвращаться число байтов), и он будет корректно разбивать каждую программу, использующую fwrite или связанные функции (например, попытаться напечатать "☺☺☺☺☺☺☺☺☺☺☺☺"
с Python 3.4).
Таким образом, ваши единственные варианты надежного вывода текста Unicode зависят от Windows (если только эти проблемы не исправлены в последней версии MSVC):
Используйте широкие функции вывода, как описано здесь: Выводить строки юникода в консольное приложение Windows
использование WriteConsoleW
(широкая версия). Убедитесь, что вы проверяете, является ли стандартный вывод или дескриптор ошибки на самом деле консолью.