LaurVas

Битва за кириллицу в консольных приложениях

windows

При написании консольных программ на языках C, C++ под Windows возникает проблема с отображением русских букв. Поэтому начинающие программисты часто делают вывод текста в своей программе транслитом, на ломанном английском, либо на каком-то промежуточном языке. Наверняка среди них популярно заблуждение о том, что русские буквы невозможно получить в принципе.

Несмотря на то, что с этой проблемой я столкнулся ещё в своей самой первой программе на C, элегантное решение нашлось только сейчас. И знаете что? Выражать свои мысли на родном языке намного приятнее, и программа выглядит аккуратно.

Скриншот сравнения разных способов решения проблемы

Кстати, в линуксе такой проблемы нет. Там свои.

В семье Windows принято умалчивать о существовании каких-то там кодировок символов, поскольку это слишком сложно для рядового пользователя. Лучше ему ничего об этом знать, потребитель должен быть счастлив. Плох тот товар, который напрягает покупателя. Конечно же я утрирую, но доля истины в этом есть. К тому же, у рядового пользователя действительно не возникает проблем с кодировками. Зачем вам может понадобиться открывать текстовый файл, написанный кем-то в кодировке KOI-8?

На практике получается, что кракозябры видели все, а откуда они берутся и как их вылечить знают немногие.

Ну да ладно. В Windows используется две кодировки: cp1251 и юникод. На самом деле есть ещё третья — cp866, оставшаяся рудиментом от MS-DOS. Именно она используется в консоли по сей день.

Первый способ

Все, что нам (вам) нужно сделать — перекодировать свои исходники в cp866. Чем? Я воспользовался notepad++. Более привычный мне редактор Sublime Text тоже умеет это делать.

Достоинства:

Никаких изменений в коде. Вам не придется подключать дополнительные библиотеки, писать лишние строки кода, менять язык с C на C++ ради использования замысловатой функции из windows.h.

Не надо менять консольный шрифт. Ваш друг, которому вы прислали на тестирование свою программу, гарантированно увидит русские буквы, независимо от шрифта в его консоли.

Полная работоспособность. Входные и выходные потоки — всё работает как положено. Разумеется, в определённых рамках.

Недостатки:

Редактор или среда, в которой вы пишете, должна дружить с этой кодировкой. Текстовые файлы сами по себе не содержат никакой информации о кодировке символов, поэтому редакторы вынуждены её угадывать. Чтобы не возникало недоразумений, хорошей манерой будет в начале файла писать что-то вроде:

//this file designed and commented in russian cp866 encoding

int main() //программа, которая ничего не делает
{
  return 0;
}

Другие способы

  • Прописать в начале волшебную строчку setlocale(LC_CTYPE, "rus"); — работает только с выходным потоком. Тем не менее, стоит взять на заметку. Это хорошая альтернатива первому способу.

  • Делать преобразования для каждой строки через CharToOem(). Не проверял, мне такое сразу не понравилось: надо подключать windows.h, теряется кроссплатформенность, код замусоривается лишними строками.

  • Подключить windows.h, использовать SetConsoleCP() и SetConsoleOutputCP() — нужно менять шрифт на Lucida Console, который мне лично не очень; теряется кроссплатформенность.