Кириллица в Console

Самый лучший способ изучения языка программирования С++ — это составление консольных программ. Структура консольного проекта максимально упрощена, так как нет графического режима, для которого необходимо подключение файлов ресурсов, классов и прочего, прочего. При составлении программы может понадобиться вывести некоторое текстовое сообщение в консоль. И если это сообщение написано на латинице, то в командной строке Windows оно будет отображаться корректно. А если текстовое сообщение написано на кириллице, то вместо передаваемого сообщения, будет отображаться непонятная последовательность букв и символов (см. Рисунок 1). Реализуем программно то, что мы хотим сделать.

// rus_text.cpp: определяет точку входа для консольного приложения.

#include “stdafx.h”
#include
using namespace std;

int main(int argc, char* argv[])
{
cout << “Кириллица в консоли\n”; // передаём текстовое сообщение в командную строку windows
system(“pause”);
return 0;
}

Программа передаёт сообщение Кириллица в консоли в командную строку Windows, и на этом завершает свою работу (см. Рисунок 1).

image35.1Рисунок 1 — Кириллица в консоли

В результате, вместо передаваемого сообщения отображается непонятная последовательность символов, называемая — козяблики. Возникает вопрос: «Почему так происходит?». Чтобы понять природу происхождения так называемых козябликов, необходимо обратиться к теме — представление символов букв в компьютерах.

Природа вычислительных машин такова, что они могут работать только с числами. Поэтому, для представления букв или символов необходимо их закодировать, то есть каждой букве или символу присвоить определённое число, которое будет являться его кодом. Так образовались таблицы кодирования символов. В связи с тем, что в мире существует более 2,5 тысяч языков, то для каждого алфавита создавались свои таблицы кодирования символов, вот почему существует большое количество таблиц кодирования символов. Так как мы программируем под Windows, то нас будут интересовать такие кодировочные таблицы: cp866, cp1251 и utf-8(стандарт Unicode). Хотя уже давно разработан единый стандарт кодирования символов – Unicode, в Windows до сих пор используются несколько кодировочных таблиц, а именно – cp866, cp1251. Использование нескольких таблиц кодирования символов и является причиной появления козябликов, вместо сообщения Кириллица в консоли.

Unicode – единый стандарт кодирования символов, позволяющий представить знаки всех письменных языков.

Таким образом стандарт Unicode присваивает каждому символу уникальный код, независимо от языка. Сейчас Unicode считается лучшим стандартом кодирования символов. Вернёмся к нашей проблеме – вывод кириллицы в консоль.

Так уж повелось, в командной строке Windows кодировка символов соответствует стандарту cp866. То есть все символы в командной строке Windows закодированы по кодировочной таблице cp866. Причём поменять кодировку в командной строке Windows нельзя. Просмотреть стандарт кодирования символов в консоли можно, с помощью команды GRAFTABL (см. Рисунок 2).

Кириллица в консоли

image35.2

Рисунок 2 — Кириллица в консоли

Во всех русскоязычных Windows кодировка cp1251 является стандартной 8 — битной кодировкой. И при создании проекта в MVS2010 этот стандарт кодирования символов наследуется проектом, то есть программой. Хотя кодировку для проекта в MVS2010 можно легко поменять, это не решает проблемы, так как консоль понимает только одну кодировку cp866, которой в MVS нет. В итоге, получается, что программа передаёт коды символов сообщения стандарта cp1251. Командная строка принимает эти коды и переводит их в символы, но уже по стандарту cp866, так как другого стандарта не знает. В итоге сообщение передано в консоль, но символы интерпретированы не правильно, вот так и появляются козяблики.

Решить данную проблему можно только одним способом — перед тем, как передать текст в консоль, необходимо его перекодировать в стандарт кодирования символов cp866. Существует несколько способов преобразования кодов знаков из одного стандарта в другой, мы воспользуемся самым простым — настройка локали.

Локаль – это набор параметров: набор символов, язык пользователя, страна, часовой пояс и др. Локаль необходима для быстрой настройки пользовательского интерфейса, в зависимости от географического положения. В С++ есть функция setlocale(), которая выполняет перекодировку символов в соответствии с требуемым языком. Эта функция определена в заголовочном файле . Переделаем программу, которая передает сообщение Кириллица в консоли в командную строку windows.

// rus_text.cpp: определяет точку входа для консольного приложения.

#include “stdafx.h”
#include
#include
using namespace std;

int main(int argc, char* argv[])
{
setlocale(LC_CTYPE, “rus”); // вызов функции настройки локали
cout << “Кириллица в консоли\n”;
system(“pause”);
return 0;
}

Функция setlocale() имеет два параметра, первый параметр – тип категории локали, в нашем случае LC_TYPE – набор символов, второй параметр — значение локали. Таким образом, сначала устанавливаем нужную локаль, в нашем случае — “rus”, после чего, можно использовать кириллицу, для вывода сообщений в консоль (см. Рисунок 3).

Кириллица в консоли
Для продолжения нажмите любую клавишу . . .

Рисунок 3 — Кириллица в консоли

Вместо аргумента “rus” можно также писать “Russian”, или оставлять пустые двойные кавычки, тогда набор символов будет такой же как и в ОС.

На первый взгляд функция setlocale() делает своё дело, но это только на первый взгляд. Суть в том, что данная функция работает только с потоком вывода, если же использовать поток ввода, то там будет все та же непонятная абракадабра. Переделаем уже разобранную нами программу, таким образом, чтобы строка сохранялась в переменную, после чего, выводилась на экран.

// rus_text.cpp: определяет точку входа для консольного приложения.

#include “stdafx.h”
#include
#include
using namespace std;

int main(int argc, char* argv[])
{
setlocale(LC_CTYPE, “rus”); // не функционирует с потоком ввода
char string[20];
cin >> string; // вводим строку, используя Кириллицу (СТРОКА СОХРАНИТСЯ В ПЕРЕМЕННОЙ НЕ КОРРЕКТНО)
cout << “\nвывод: “<< string << endl; // ввывод строки
system(“pause”);
return 0;
}

Результат работы программы на рисунке 4.
CppStudio.com

Кириллица в консоли

вывод: ?ЁаЁ<<Ёж
Для продолжения нажмите любую клавишу . . .

Рисунок 4 — Кириллица в консоли

Как видно из рисунка 4, слово вывод напечаталось корректно, а вот содержимое строки string – нет. А всё потому, что функция setlocale() работает только с потоком вывода. Но как же быть с потоком ввода??? Есть немало способов решать данную проблему, мы рассмотрим лишь один из них. Для этого подключаем к проекту заголовочный файл . В файле содержатся прототипы функций SetConsoleCP() и SetConsoleOutputCP(), они-то нам и нужны. Аргументом этих функций является идентификатор кодовой страницы, нужная нам страница win-cp 1251. Функция SetConsoleCP() устанавливает нужную кодовую таблицу, на поток ввода, тогда как функция SetConsoleOutputCP() устанавливает нужную кодовую таблицу, на поток вывода.
// прототипы функций
BOOL WINAPI SetConsoleOutputCP ( __in UINT wCodePageID); // установка кодовой страницы в поток вывода
BOOL WINAPI SetConsoleCP ( __in UINT wCodePageID); // установка кодовой страницы в поток ввода
// где wCodePageID – идентификатор кодовой таблицы

Есть один весомый недостаток у данных функций — они работают со шрифтом Lucida Console. По умолчанию в консоли стоит шрифт Consolas. Поэтому в командной строке необходимо настроить используемый шрифт. Для этого открываемcmd, заходим в свойства, в закладке Шрифт выбираем Lucida Console, нажимаем ОК и на этом настройка завершена (см. Рисунок 5).

Кириллица в консоли

image35.5

Рисунок 5 — Кириллица в консоли

Если все сделали правильно, то в консоли корректно будут отображаться символы Кириллицы. Теперь вместо функции setlocale() воспользуемся этими функциями.

// rus_text.cpp: определяет точку входа для консольного приложения.

#include “stdafx.h”
#include
#include
using namespace std;

int main(int argc, char* argv[])
{
SetConsoleCP(1251);// установка кодовой страницы win-cp 1251 в поток ввода
SetConsoleOutputCP(1251); // установка кодовой страницы win-cp 1251 в поток вывода

char string[20];
cin >> string; // вводим строку, используя Кириллицу
cout << “\nвывод: “<< string << endl; // ввывод строки
system(“pause”);
return 0;
}

Результат работы программы показан на рисунке 6.

Кириллица в консоли

вывод: Кириллица
Для продолжения нажмите любую клавишу . . .

Рисунок 6 — Кириллица в консоли

Источник: http://cppstudio.com/post/435/