Страницы

Поиск по вопросам

среда, 31 октября 2018 г.

Отображение кириллицы в CLion

Нужна помощь: не отображается кириллица в терминале CLion. Вот так выглядит надпись "Привет, Мир!":
╨Я╤А╨╕╨▓╨╡╤В, ╨Ь╨╕╤А!
Вот что будет с кодировкой windows-1251
╧ЁштхЄ, ╠шЁ!


Ответ

Почему так происходит?
CLion по дефолту использует UTF-8 для хранения файлов с исходным кодом. Строка "Привет, Мир!" будет представлять собой последовательность (в файле с исходником):
D0 9F D1 80 D0 B8 D0 B2 D0 B5 D1 82 2C 20 D0 9C D0 B8 D1 80 21
Как видите, на 12 символов исходной строки, получили 21 байт (т.к. кириллические символы занимают больше одного байта).
Компилятор GCC по умолчанию читает исходники в кодировке UTF8, если не указать другую через ключ -finput-charset. Таким образом эта последовательность байтов в неизменном виде сохранится в исполняемый файл.
При запуске программы на исполнение, CLion использует стандартный cmd.exe, который по умолчанию скорей всего у вас работает в кодировке CP866. В которой наша последовательность байтов будет отображена как:
╨Я╤А╨╕╨▓╨╡╤В, ╨Ь╨╕╤А!
(что вы и видите в терминале CLion)

Что делать?
Вариант 1
Сменить кодировку файла на IBM866 (то же, что и CP866) (настройки - File Encodings) (сам файл перекодировать, если там уже был текст на русском). Теперь кириллица будет сохраняться в файле с исходным текстом в кодировке CP866 (один байт на символ), в том же виде попадать в исполняемый файл и нормально отображаться в консоли CLion. Разумеется, использовать CP866 в 17-м году, без особых на то оснований, это некультурно. Кроме того придется ограничить себя только символами из CP866
Вариант 2
Вставить в начало свой программы:
system("chcp 65001");
или (потребует #include ):
SetConsoleOutputCP(CP_UTF8);
Консоль переключится в UTF-8, все будет отображаться как надо. Но только при использовании низкоуровневых операций вывода типа puts("Привет, Мир!");. Если выводить через std::cout, то возможен вывод типа ��ривет, Мир!. Это связано с тем, что Windows API для вывода в консоль ожидает видеть в каждом вызове законченную строку. И если оператор basic_ostream::operator<<(char*) для символа 'П' выполнит два API вызова (с D0 и 9F), то они не сольются в одну букву 'П', а будут интерпретированы и отображены как два разных символа (��).

Предостережение
При использовании UTF-8 в своей программе, например при хранении в std::string, следует помнить, что операции над строками могут дать не очевидные результаты (т.к. один символ теперь может занимать от 1 до 4 байтов).
Кроме вывода, аналогичные проблемы ожидают и при вводе из std::cin. Таким образом, единственное прозрачное решение для Windows (даже десятки), пока остается использование латиницы.

Комментариев нет:

Отправить комментарий