Думаю, нет нужды говорить о том, что обучаться программированию имеет смысл на примерах с консольным интерфейсом. Не требующая специфических знаний в области GUI-библиотек, стандартизованная для всех операционных систем, имеющая встроенную поддержку в стандартных библиотеках большинства языков, консоль – идеальный вариант.
И C++ – не исключение. Поддержки графического интерфейса пользователя в стандартной библиотеке нет, и не предвидится ее включение из-за особенностей философии языка.
Часто возникающей проблемой с консольными программами (у русских программистов) является вывод кириллицы. Точнее его невозможность.
Отметим также, что проблема эта возникает исключительно у Windows-программистов. Имя проблеме – кодировки.
Если вы о них “что-то слышали, но что это такое – не уверены”, очень советую прочитать эту статью.
Нет, правда, настоятельно советую.
Даже если нет времени – распечатайте и прочитайте в автобусе.
Автор статьи – Джоэл Спольски. Если вы не знаете, кто это такой – срочно узнайте, и больше никогда никому не говорите, что не знаете, кто такой Джоэл Спольски. Быть программистом и не знать, кто такой Джоэл Спольски, – нонсенс.
Но ближе к делу.
Дело в том, что в русскоязычных версиях Microsoft Windows в качестве основной кодировки принята ANSI, которая стандартизована одноименным комитетом, и для разных языков надстраивает ASCII-символы разными кодовыми страницами. Для нашего Отечества это cp1251. Консоль же Windows в противоположность использует устаревшую OEM-кодировку, на наречии Microsoft – кодовую страницу cp866. Зачем – Бог знает. Наверное, чтобы мы могли насладиться программами, написанными лет 20 назад, с красивыми окошками и кнопочками в стиле DOS.
Из-за несоответствия кодировок (т.е. способов интерпретации кодов символов в их графические представления) мы и видим на экране “╧ЁштхЄ!” вместо “Привет!”.
Если вы чего-то не поняли из предыдущего объяснения, рекомендую все же прочитать статью по ссылке выше, поскольку здесь – только краткое описание проблемы, а исторический фон и установление причинно-следственных связей – материал столь обширный, что дублировать его я не вижу смысла.
Вместо этого я бы хотел рассмотреть несколько способов решения этой проблемы. Точнее, рассмотрим мы один метод, а на остальные я приведу ссылки.
Есть в Си волшебная функция
char* setlocale (int category, const char* locale)
Она устанавливает в программе т.н. локаль (locale) – набор национальных параметров, включающий помимо форматов даты, времени, валюты и т.п., характерных для данной местности, кодировку символов, в ней употребляемую.
Идентификатор локали – строка. Ее формат определяется по-разному. Рассмотрим различные варианты применительно к России.
1) В Win32API это число 1049. Логично, черт возьми.
2) В Java, .NET и Windows начиная с версии 6.0 (“Vista”) используется более стандартизованный способ представления локали – строка формата
язык-РЕГИОН
Применительно к нам – “ru-RU”.
3) В POSIX-системах (UNIX, GNU/Linux) используется стандартизованный формат
язык_регион.кодировка
В нашем случае – “Russian_Russia.1251″
А кто сказал, что будет легко?
Вернемся к функции setlocale(). Первый параметр – целое число, в качестве передаваемого значения обычно используют константы, объявленные в <clocale> и говорящие, какие категории нам надо локализовывать. Нам подойдет константа LC_CTYPE, которая влияет на функции, имеющие дело с символами.
Второй параметр функции – идентификатор локали. Туда можно передавать следующие значения:
1) Сокращение – “rus”.
2) Название языка полностью – “Russian”.
3) Номер кодовой страницы – “.1251″.
Примечание: Если передать номер используемой в консоли OEM-кодировки (“.866″), то символы в программе будут к ней преобразованы, что также является решением нашей проблемы. Этого же можно добиться, передав строку “.OCP”, которая означает OEM Code Page и устанавливает локаль с текущей OEM-кодировкой операционной системы.
4) Идентификатор в формате POSIX – “Russian_Russia.1251″
5) Пустую строчку – “”. Если мы так поступим, в программе будет установлена кодовая страница операционной системы по умолчанию, в нашем случае это соответствует cp1251.
Т.е. установка локали в простейшем случае производится следующим образом:
setlocale(LC_CTYPE, "");
Полноценный пример:
#include<iostream>
#include<clocale>
using namespace std;
int main()
{
setlocale(LC_CTYPE, "");
cout << "Русский текст?! Да ладно!" << endl;
cin.get();
return 0;
}
Ссылки для дальнейшего самосовершенствования:
Список различных кодировок (Википедия)
Описание функции setlocale() (англ.)
Способы преобразования кодировок в C++
Сайт Майкрософта. Кодировки OEM 866 и Windows 1251
Спасибо за статью, в тему) Не сталкивались случайно с вопросом узнавания наличия желаемой кодировки у пользователя в *NIX?
P. S. Первый линк не открывается :/
За статью на здоровье
Первый линк у меня открывается, странно… Пробовал в разных браузерах.
Узнавание наличия локали:
try
{
locale WeHave(“russian”);
cout << WeHave.name().c_str() << endl;
}
catch(runtime_error& e )
{
cout << e.what() << endl;
}
По-моему, класс locale должен быть стандартизован, и, следовательно, может использоваться и под никсами, и не под ними.
А вообще в Линуксе благодаря тотальной поддержке прекрасной кодировки utf-8 ничем из описанного в статье заниматься не приходится.
Просто виндовая консоль подгадила :/
В одном из следующих постов разберем Юникод.
С UTF-8 свои заморочки. Дело в том, что в памяти символы занимают разное количество байтов (английские буквы, пунктуация и т. п. – 1, а большинство других, русские буквы в том числе – 2). При этом ввод-вывод строк проблем не вызывает, а вот попытка разобрать строку на отдельные символы приводит к появлению вопросиков (они же квадратики).
Спасибо за рецепт!
Поддержка UTF-8 действительно стала широко распространена, но я столкнулся с прогой, выводившей сообщения на русском в KOI8-R, так как в организации, где она была написана, использовалась такая кодировка. У себя-то я исходники конвертнул и скомпилировал, но подумалось, что это не тру путь при создании программ
Сегодня у меня тоже сайт открылся, не знаю что за глюк тогда был…
Уведомление: Текущие время и дата « C++ для людей
Спс, хоть всё я это и знаю, но почитать не отказался). Вот только про utf-8 поподробней плыз))
Да, все руки не доходят этим заняться. В течение лета, думаю, напишу.
Благодарю, друг, от имени всех начинающих!
Видел кучу ответов на форумах, но почему-то нигде не заметил одного интересного варианта. Наверное плохо искал.
system(“echo Текст на русском”);
должно всё выводить по-русски.
Касательно всей подоплеки кодировок и т.д. я знал и до того, а вот как записать это в СИшке еще не знал
За это и спасибо