По поводу использования русских букв в C/C++
Только что, то есть 1 января 2002 года примерно в 18 час 48 минут я получил второе письмо от того же автора на затронутую мною на уроке 9 тему. Оба письма написаны Mike Koshelev'ым. Я опробовал рекомендации Mike Koshelev'a. Помещаю здесь результаты этого опробования. Ниже на рисунках Вы можете сами все увидеть, как оно будет, если придерживаться методики Mike. Сегодня я хочу дать Вам материалы опробования, провести анализа и сделать некоторые выводы по результатам этого анализа. Прежде всего познакомимся с упомянутыми письмами.
Вот первое письмо от 31 декабря 2001 года.
Письмо было получено от Mike Koshelev'a так кстати. Большое ему за это СПАСИБО !!!
Hello Юрий,
Русские буквы в окне редактора фиксятся очень просто - Options->Environment->Editor->Display поле Font заменить на Courier New Cyr. Удобно писать комментарии на русском. А вот как сделать консольный вывод в нормальной кодировке и чтобы в редакторе наблюдать нормальные сообщения я не знаю. Поэтому комментарии пишу на русском а сообщения на английском.
Вызовем вначале программу Borland C/C++ 5.2. Далее войдем в раздел "Option" во второй строке программы - в строке меню команд. Откроется ниспадающее меню (окно) программы. Выберем в нем строку "Environment" и щелкнем по ней дважды левой кнопкой манипулятора "мышь". Все вышесказанное показано ниже на рисунке.
Перед нами откроется окно "Environment Option". Выберем в левой части окна строку "Editor", помеченную плюсом, и щелкнем по ней дважды левой кнопкой мыши. Плюсик заменится на минус и перед нами предстанет детальное содержание строки "Editor".
Выберем далее в детализированом списке, полученном из строки "Editor", строку "Display" и щелкнем по ней, как прежде, левой кнопкой мыши. Получим окно, в котором будем переустанавливать наименование шрифта со знаками кириллицы. Ниже на рисунке показано это окно.
В правой части окна выберем FONT и, щелкнув по треугольнику, обращенному острием вниз, найдем наименование переустанавливаемого нами шрифта Courier New Cyr и переустановим новый шрифт.
Это позволит нам иметь русские буквы в двойных кавычках в протоколе трансляции ( в тексте нашей программы в окне компилятора Borland C/C++ 5.2).
Далее выполним решение по программе, полученной после выполнения трансляции. В этой программе на этапе трансляции присутствовали буквы русского алфавита. Но они исчезли в полученном решении, что подтверждают приведенные ниже рисунки.
Русские буквы желательно иметь на всех этапах работы в С/C++. Однако, как показывает проверка, методика Mike этого не обеспечивает. По моему разумению самое главное, чтобы они, то есть русские буквы, присутствовали на этапе решения задачи. Но они или выдаются в протоколе трансляции, и тогда их нет в самом решении, или их нет в протоколе трансляции, но зато они есть в распечатке ( или вернее в окне решения задачи ), что важнее, как мне кажется, не так ли?
Вначале я обрадовался, когда получил русские буквы в протоколе трансляции моей учебной программы, предназначенной для испытания наличия русских букв. Потом я с превеликим огорчением обнаружил, что в этом случае после трансляции русские буквы не просматриваются в окне процесса решения задачи. Вот как обстоит дело.
Так что методика руссификации, которой пользуется Mike, вполне приемлема, но она, к сожалению, не дает все же полной возможности использовать русские буквы на всех этапах работы в языке С/C++. Аналогично и та методика, о которой рассказывалось на предыдущем уроке 9, тоже не дает русских букв на всех этапах работы с транслятором. Но самое главное, что она дает их в решении задачи. А это куда важнее. То есть это самое главное для тех пользователей, которые работают с русским алфавитом, как, например, мы - входящие в постсоветское пространство СНГ.
Итак, подведем итог нашим исследованиям. Как следует из проведенного эксперимента, согласно полученным от Mike рекомендациям, в самом решении нет русских букв... Пожалуйста, проделайте все это сами, и тогда Вы еще лучше поймете наши выводы. Если кто-то из учеников знает, как сделать полную руссификацию транслятора Borland C/C++ 5.2, то есть чтобы одновременно и протокол трансляции, и решение задачи после трансляции отображались русскими буквами, прошу поделиться этими знаниями со всеми слушателями и читателями моих уроков. Пока же предложенное Mike решение пригодно и может быть использовано, но оно все же не решает проблему русских букв на всех этапах работы в языке С/C++. Так что мои рекомендации остаются, как я полагаю, в силе.
Ниже я привожу второе письмо Mike Koshelev'a, в котором он разъясняет свою позицию и приводит свои аргументы "за" и "против" по данному вопросу.
Hello Юрий!
Tuesday, January 01, 2002, 6:48:11 PM.
Как я и писал данный способ работает только в окне редактора кода, т.е. можно писать комментарии на русском языке. Но вывод в консольное окно происходит похоже в другой кодировке, и я не знаю как это пофиксить. Поэтому комментарии я пишу на русскома, а выводимые сообщения на английском, благо я хорошо знаком с этим языком. :) На сопутствующем скрин-шоте видно окно редактора с комментариями. Мне просто совершенно не нравится идея готовить текст в отдельном редакторе, там ведь нет выделения синтаксиса и вообще...
Рекомендуемая литература:
- Нейбауэр Алан. Моя первая программа на Си/Си++. Перевод с англ. - СПб.: Питер, 1996. - 368 с.: ил.
- Березин Б.И., Березин С.Б. Начальный курс С и С++. - М,: ДИАЛОГ_МИФИ, 1996. - 288 с.
- Подбельский В.В., Фомин С.С. Программирование на языке Си: Учеб. пособие. - М.: Финансы и статистика, 1998. - 600 с.: ил.
- Джонс Р., Стюарт Я. Программируем на Си/Пер. с англ. и предисл. М.Л. Сальникова, Ю.В. Сальниковой. - М.: Компьютер, ЮНИТИ, 1994. - 236 с.: ил.
- Скляров В.А. Программирование на языках Си и Си++: Практ. пособие. - М.: Высш. шк., 1996. -240 с.: ил.
- Пашенков В.В. Язык программирования Си. - М.: Центр НТТМ "Алгоритм", 1990. - 76 с.
- УинерР Р. Язык Турбо Си: Пер. с англ. -М.: Мир, 1991. - 384 с.: ил.
Оставить комментарий
Комментарии
#include <iostream>
using namespace std;
int main() {
setlocale(LC_ALL, ".OCP");
char prompt[21] = "Введите строку...";
wstring str;
wcout << prompt << endl;
wcin >> str;
wcout << "Введено: " << str;
return 0;
}
И ввод и вывод нормально. Например:
#include <iostream>
using namespace std;
int main() {
setlocale(LC_ALL, ".OCP");
wchar_t prompt[21] = L"Введите строку...";
wstring wstr;
wcout << prompt << endl;
wcin >> wstr;
wcout << L"Введено: " << wstr;
return 0;
}
Эта тема сейчас обсуждается в форуме - http://forum.codenet.ru/q71209/
//----------------------------------------------------------
// Кодировка этого файла Windows-1251
//-----------------------------------------------------------
// Пример на русификацию + еще экономим размер бинарника,
// используя stdio вместо здорового iostream
#include <locale.h>
#include <stdio.h>
int main(int argc, char *args[])
{
setlocale(LC_ALL, "rus");
printf("Строка на русском!!!\n");
}
Далее в main() ставил строчку:
setlocale(LC_ALL, "Russian");
Для вывода русских строк в исходнике писал типа:
wcout << L"Русская строчка";
(wcout вместо cout).
Это в винде. А в линухе вообще проблем нет.
system("chcp 1251");
У меня она тоже ни к чему не привела.
Только CharToOEM дает решение, но не слишком удобное
SetConsoleOutputCP();
Лично я начитавшись про это да и на других форумах
опробовал все мыслимые варианты под Windows (компиляторы Borland C++ Builder и gcc 4.9.9.2 for Windows)
Все комбинации типа
SetConsoleCP(GetOEMCP());
SetConsoleOutputCP(GetOEMCP());
SetConsoleCP(1851);
SetConsoleOutputCP(1851);
setlocale(LC_CTYPE,"Russian"); //?
setlocale(LC_ALL, ".OCP"); char c;
setlocale (LC_ALL,".1251");
setlocale(LC_ALL, "Russian");
Ни к ЧЕМУ НЕ ПРИВОДИЛИ!!!
setlocale(LC_ALL, "Russian");
и ни каких проблем)
Более подробно об этом и другом с примером кода можете прочитать в моей статье...
http://winmain.epage.ru/WinConsole.htm
1. BOOL SetConsoleCP(UINT wCodePageID);
2. BOOL SetConsoleOutputCP(UINT wCodePageID);
Вот что о них пишут в MSDN:
The SetConsoleCP function sets the input code page used by the console associated with the calling process. A console uses its input code page to translate keyboard input into the corresponding character value.
The SetConsoleOutputCP function sets the output code page used by the console associated with the calling process. A console uses its output code page to translate the character values written by the various output functions into the images displayed in the console window.
Разработчики windows решили оставить DOS-кодировку для сохранения совместимости со старыми консольными дос программами, при этом использовать win кодировку не кто не запрещает, для этого и существуют эти функции.
#include <iostream.h>
unsigned int Length (const unsigned char s[])
{ int len = 0; while (s[len++]); return len - 1; }
void WinToDos (unsigned char t[])
{
int n = Length(t);
for (int i = 0; i < n; i++)
{
if (t > 239) { t -= 16; continue; }
if (t > 191) { t -= 64; continue; }
if (t == 184) { t = 241; continue; }
if (t == 168) t = 240;
}
}
int main ()
{
unsigned char text1[] = "Нужный нам текст для вывода";
WinToDos(text1);
cout << text1;
}
Наверное, можно элегантнее сделать, но, думаю, мысль ясна. Кстати, код - полностью работоспособный :-)
#include <windows.h>
void printru(char* s)
{
char s1[81];
CharToOem(s,s1);
printf(s1);
}
// единственное, неработает как printf, но это легко решается, если рассмотреть суть проблемы:
Мы набираем текст в кодировке ASCII, но так как запускаем прогу в среде не ДОС, то вывод на консоль идеть в OEM,(или наоборот, не помню, да и не столь важно), поэтому можно сделатьфункцию, которая буде высчитывать смещение между буквами в разных кодировках, и менять их, возвращая исправленные символы в вызывающую функцию, тогда уже можно становиться использовать управляющие строки:
char* cyr(char* s)
{
unsigned char* p=s;
while (*p)
{
if (*p==184)
*p+=57;
else
{
if (*p==168)
*p+=72;
else
{
if (*p>=192&&*p<=239)
*p-=64;
else
{
if (*p>=240&&*p<=255)
*p-=16;
}
}
}
p++;
}
return s;
}
данную функцию можно вызывать в таком виде:
printf(cyr("%d",2*2));
#include <clocale>
using namespace std;
setlocale(LC_CTYPE,"Russian"); //?
У меня все работает на VS2005.
Включение инструмента "File convert" в компилятор.
Остается только включить в состав инструментов компилятора такой важный для нас инструмент, как конвертация или перекодировка. Этот инструмент назовем: "File convert". Проделаем до конца устанвку инструмента под именем "File convert" в компилятор. Как и прежде, войдем в раздел "Options". Выберем теперь в ниспадающем меню строку "Tools".
Щелкнем мышью по этой строке. Откроется окно "Tools".
Найдем в нем кнопку опции "New" и включим ее легким щелчком мыши.
Появится новое окно, в котором нужно зарегистрировать новый для компилятора инструмент.
Назовем этот новый инструмент: "File convert".
Занесем имя инструмента в строку "Name:".
Далее в строку "Path:" занесем имя программы конвертации fconvert.exe.
Чуть ниже в следующей строке " Command Lines:"запишем $SAVE ALL.
В последней стоке "Help Hint:" поместим обозначение convertion OEM-ANSI-OEM.
В заключение нажмем кнопку "Ok".
Новый инструмент включен в меню "Tolls" компилятора.
Действительно, сведения о нем уже находятся в окне Tools".
Вспомните, что мы начинали регистрацию нового инструмента именно с этого окна, когда нажали здесь чуть раньше кнопку "New".
Убедимся в этом, войдя также в раздел "Tools" из второй строки окна компилятора.
Итак, мы еще раз убедились, что новый инструмент компилятора успешно включен нами в раздел "Tools".На этом новый материал урока изложен.
Можно использовать API-шную функцию SetConsoleOutputCP - "SetConsoleOutputCP(1251);" в NT/2000/XP. Правда работает это только если консоль использует шрифт "Lucida Console"
Писать можно будет этим шрифтом только если установить соотв. раскладку. Как-то я пробовал такое, только иметь 3 раскладки напрягает.
>> Мне просто совершенно не нравится идея готовить текст в >> отдельном редакторе, там ведь нет выделения синтаксиса >> и вообще...
Смотря в каком, в Folder Manager и DosNav есть(редактор там весьма продвинутый), для Far есть плугин, главное что бы не было предубеждения против консольных программ :).
Есть несоколько способов это обойти.
1-ый способ:
Писать всю программу в кодировке 866.
Для этого надо выбрать шрифт с этой кодировакой в настройках редактора, например, "Terminal".
2-ой способ - писать программу используя Unicode.
3-ый Перекодировать все строки при запуске программы или непосредственно при выводе на экран (CharToOem, OemToChar)
(не самый удобный способ, однако если его нормально реализовать, можно использовать в других прогах)
4-ый Вынести все сообщения в отдельный файл и редактировать его другим редактром (Far, DosNavigator, Folder Manager и т.д.). В некоторых GUI прогах, где используется отладочная выдача в консоль - я так и делаю.