Setconsolecp 1251 ошибка

0 / 0 / 0

Регистрация: 09.03.2017

Сообщений: 21

1

08.05.2017, 11:01. Показов 17628. Ответов 5


Студворк — интернет-сервис помощи студентам

Необходимо сделать так, чтобы программа воспринимала кириллицу в потоках ввода и вывода (setlocale не подходит, так как она работает только с потоком вывода). Решил использовать функции SetConsoleCP(1251) и SetConsoleOutputCP(1251), подключил библиотеки #include <windows.h>. Компилятор не ругается, но в итоге в программа все равно не воспринимает кириллицу — крякозябрики показывает.

В чем ошибка, и есть ли простые замены функциям SetConsoleCP() и SetConsoleOutputCP() ? Работаю в CodeBlocks. Возможно, где-то в настройках нужно включить поддержку этих функций?



0



Programming

Эксперт

94731 / 64177 / 26122

Регистрация: 12.04.2006

Сообщений: 116,782

08.05.2017, 11:01

5

21 / 21 / 10

Регистрация: 11.09.2015

Сообщений: 103

08.05.2017, 11:52

2

sherlock440,Странно, у меня работают. Попробуй, может повезёт
system («chcp 1251 > nul»);



0



670 / 216 / 88

Регистрация: 21.07.2016

Сообщений: 1,036

Записей в блоге: 2

08.05.2017, 12:01

3

Миниатюры

Не работают функции SetConsoleCP() и SetConsoleOutputCP()
 



1



1718 / 567 / 187

Регистрация: 12.03.2016

Сообщений: 2,169

08.05.2017, 12:03

4

SetConsoleCP() и SetConsoleOutputCP() оставьте.
Запустите любое консольное приложение

Не работают функции SetConsoleCP() и SetConsoleOutputCP()

Откройте меню, щелкнув по левому верхнему углу.
Умолчания / Шрифты
В шрифтах установите Lucida Console
Запустите проект заново.
Должно заработать.



2



0 / 0 / 0

Регистрация: 08.09.2021

Сообщений: 1

25.09.2021, 08:16

5

У меня такая же проблема с SetConsoleCP(1251) и SetConsoleOutputCP(1251), но по вашим инструкциям ничего не работает(



0



17423 / 9256 / 2263

Регистрация: 30.01.2014

Сообщений: 16,208

25.09.2021, 12:40

6

RomanSCHIK, файл исходника, если русские строки непосредственно в нем находятся, тоже должен быть в таком случае в cp1251. Если он у вас в UTF-8, например, то работать SetConsoleOutputCP для таких строк не будет.



0



Для данной задачи существует множество решений. Если вам нужно быстрое и не обязательно универсальное решение, чтобы сильно не разбираться, прокручивайте к разделу «Менее правильные, но пригодные решения».

Правильное, но сложное решение

Для начала, проблема у консоли Windows состоит в том, что её шрифты, которые стоят «по умолчанию», показывают не все символы. Вам следует сменить шрифт консоли на юникодный, это позволит работать даже на английской Windows. Если вы хотите поменять шрифт только для вашей программы, в её консоли нажмите на иконку в левом верхнем углу → Свойства → Шрифт. Если хотите поменять для всех будущих программ, то же самое, только заходите в Умолчания, а не Свойства.

Lucida Console и Consolas справляются со всем, кроме иероглифов. Если ваши консольные шрифты позволят, вы сможете вывести и , если нет, то лишь те символы, которые поддерживаются.

Дальнейшее рассмотрение касается лишь Microsoft Visual Studio. Если у вас другой компилятор, пользуйтесь предложенными на свой страх и риск, никакой гарантии нету.

Теперь, кодировка входных файлов компилятора. Компилятор Microsoft Visual Studio (по крайней мере, версии 2012 и 2013) компилирует исходники в однобайтных кодировках так, как будто бы они на самом деле в ANSI-кодировке, то есть для случая русской системы — CP1251. Это означает, что кодировка исходников в CP866 — неправильна. (Это важно, если вы используете L"..."-строки.) С другой стороны, если вы храните исходники в CP1251, то эти же исходники не будут нормально собираться на нерусской Windows. Поэтому стоит хранить исходники в Unicode (например, UTF-8).

Настроив среду, перейдём к решению собственно задачи.

Правильным решением является уйти от однобайтных кодировок, и использовать Unicode в программе. При этом вы получите правильный вывод не только кириллицы, но и поддержку всех языков (изображение отсутствующих в шрифтах символов будет отсутствовать, но вы сможете с ними работать). Для Windows это означает переход с узких строк (char*, std::string) на широкие (wchar_t*, std::wstring), и использование кодировки UTF-16 для строк.

(Ещё одна проблема, которую решает использование широких строк: узкие строки при компиляции кодируются в однобайтную кодировку используя текущую системную кодовую страницу, то есть, ANSI-кодировку. Если вы компилируете вашу программу на английской Windows, это приведёт к очевидным проблемам.)

Вам нужно _setmode(_fileno(...), _O_U16TEXT); для переключения режима консоли:

#include <iostream>
#include <io.h>
#include <fcntl.h>

int wmain(int argc, wchar_t* argv[])
{
    _setmode(_fileno(stdout), _O_U16TEXT);
    _setmode(_fileno(stdin),  _O_U16TEXT);
    _setmode(_fileno(stderr), _O_U16TEXT);

    std::wcout << L"Unicode -- English -- Русский -- Ελληνικά -- Español." << std::endl;
    // или
    wprintf(L"%s", L"Unicode -- English -- Русский -- Ελληνικά -- Español.n");

    return 0;
}

Такой способ должен работать правильно с вводом и выводом, с именами файлов и перенаправлением потоков.

Важное замечание: потоки ввода-вывода находятся либо в «широком», либо в «узком» состоянии — то есть, в них выводится либо только char*, либо только wchar_t*. После первого вывода переключение не всегда возможно. Поэтому такой код:

cout << 5;            // или printf("%d", 5);
wcout << L"привет";   // или wprintf(L"%s", L"привет");

вполне может не сработать. Используйте только wprintf/wcout.


Если очень не хочется переходить на Unicode, и использовать однобайтную кодировку, будут возникать проблемы. Для начала, символы, не входящие в выбранную кодировку (например, для случая CP1251 — базовый английский и кириллица), работать не будут, вместо них будет вводиться и выводиться абракадабра. Кроме того, узкие строковые константы имеют ANSI-кодировку, а это значит, что кириллические строковые литералы на нерусской системе не сработают (в них будет зависимая от системной локали абракадабра). Держа в голове эти проблемы, переходим к изложению следующей серии решений.

Менее правильные, но пригодные решения

В любом случае, поставьте юникодный шрифт в консоли. (Это первый абзац «сложного» решения.)

Убедитесь, что ваши исходники в кодировке CP 1251 (это не само собой разумеется, особенно если у вас не русская локаль Windows). Если при добавлении русских букв и сохранении Visual Studio ругается на то, что не может сохранить символы в нужной кодировке, выбирайте CP 1251.

(1) Если компьютер ваш, вы можете поменять кодовую страницу консольных программ на вашей системе. Для этого сделайте вот что:

  1. Запустите Regedit.
  2. На всякий пожарный экспортируйте куда-нибудь реестр (этот шаг все почему-то пропускают, так что когда всё сломается, мы вас предупреждали).
  3. В разделе HKEY_CURRENT_USERConsole найдите ключ CodePage (если нету, создайте ключ с таким названием и типом DWORD).
  4. Установите значение по ключу (левая клавиша/изменить/Система счисления = десятичная) на 1251.
  5. Не забудьте перегрузиться после изменений в реестре.

Преимущества способа: примеры из книг начнут работать «из коробки». Недостатки: смена реестра может повлечь за собой проблемы, кодировка консоли меняется глобально и перманентно — это может повлиять сломать другие программы. Плюс эффект будет только на вашем компьютере (и на других, у которых та же кодировка консоли). Плюс общие проблемы неюникодных способов.

Примечание. Установка глобальной кодовой страницы консоли через параметр реестра HKEY_CURRENT_USERConsoleCodePage не работает в Windows 10, вместо него будет использована кодовая страница OEM — предположительно баг в conhost. При этом установка кодовой страницы консоли на уровне конкретного приложения (HKEY_CURRENT_USERConsole(путь к приложению)CodePage) работает.

(2) Вы можете поменять кодировку только вашей программы. Для этого нужно сменить кодировку консоли программным путём. Из вежливости к другим программам не забудьте потом вернуть кодировку на место!

Это делается либо при помощи вызова функций

SetConsoleCP(1251);
SetConsoleOutputCP(1251);

в начале программы, либо про помощи вызова внешней утилиты

system("chcp 1251");

(То есть, у вас должно получиться что-то вроде

#include <cstdlib>  

int main(int argc, char* argv[])
{
    std::system("chcp 1251");
    ...

или

#include <Windows.h>

int main(int argc, char* argv[])
{
    SetConsoleCP(1251);
    SetConsoleOutputCP(1251);
    ...

и дальше обыкновенный код программы.)

Можно обернуть эти вызовы в класс, чтобы воспользоваться плюшками автоматического управления временем жизни объектов C++.

Пример:

#include <iostream>
#include <string>

int chcp(unsigned codepage)
{
    // составить команду из кусочков
    std::string command("chcp ");
    command += codepage;
    // выполняем команду и возвращаем результат
    return !std::system(command.c_str());
}

// этот код будет запущен перед main
static int codepage_is_set = chcp(1251);

(если выполняете задание из Страуструпа можно вставить в конец заголовочного файла std_lib_facilities.h)

Или так:

#include <windows.h>

class ConsoleCP
{
    int oldin;
    int oldout;

public:
    ConsoleCP(int cp)
    {
        oldin = GetConsoleCP();
        oldout = GetConsoleOutputCP();
        SetConsoleCP(cp);
        SetConsoleOutputCP(cp);
    }

    // поскольку мы изменили свойства внешнего объекта — консоли, нам нужно
    // вернуть всё как было (если программа вылетит, пользователю не повезло)
    ~ConsoleCP()
    {
        SetConsoleCP(oldin); 
        SetConsoleOutputCP(oldout);
    }
};

// и в программе:    
int main(int argc, char* argv[])
{
    ConsoleCP cp(1251);
    std::cout << "русский текст" << std::endl;
    return 0;
}

Если вам нужен не русский, а какой нибудь другой язык, просто замените 1251 на идентификатор нужной кодировки (список указан ниже в файле), но, разумеется, работоспособность не гарантируется.

Остались методы, которые тоже часто встречаются, приведём их для полноты.

Методы, которые работают плохо (но могут помочь вам)

Метод, который часто рекомендуют — использование конструкции setlocale(LC_ALL, "Russian"); У этого варианта (по крайней мере в Visual Studio 2012) гора проблем. Во-первых, проблема с вводом русского текста: введённый текст передаётся в программу неправильно! Нерусский текст (например, греческий) при этом вовсе не вводится с консоли. Ну и общие для всех неюникодных решений проблемы.

Ещё один метод, не использующий Unicode — использование функций CharToOem и OemToChar. Этот метод требует перекодировки каждой из строк при выводе, и (кажется) слабо поддаётся автоматизации. Он также страдает от общих для неюникодных решений недостатков. Кроме того, этот метод не будет работать (не только с константами, но и с runtime-строками!) на нерусской Windows, т. к. там OEM-кодировка не будет совпадать с CP866. В дополнение можно так же сказать что эти функции поставляются не со всеми версиями Visual Studio — например в некоторых версиях VS Express их просто нет.


Источники:

  1. Как выводить на экран и вводить данные типа wchar_t[]?
    • к сожалению, автор того вопроса пользовался компилятором MinGW под Cygwin и WinXP, что делает большинство современных решений неприменимыми.
  2. Output unicode strings in Windows console app
  3. Conventional wisdom is retarded, aka What the @#%&* is _O_U16TEXT?
  4. What’s the difference between printf(“%s”), printf(“%ls”), wprintf(“%s”), and wprintf(“%ls”)?
  5. Русский язык в исходном коде в Dev C++
  6. Code Page Identifiers

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

Возникла проблема с отображением русских букв

Если нужно быстрое решение данной проблемы, то можно сразу пролистать вниз, ибо сначала я расскажу о том, как возникла эта проблема у меня и о том, как я искал решение.

На языке C++ программирую под ОС Linux, использую компилятор GCC. С проблемой неправильного отображения русских букв я не сталкивался. В момент написания статьи я нахожусь далеко от своего компьютера, могу довольствоваться лишь скромненьким ноутбуком с установленной ОС Windows Seven. Захотелось покодить и я установил на него интегрированную среду разработки Dev-C++ 5.10(использует компилятор TDM-GCC 4.8.1 на базе GCC 4.8.1). Кстати, она уже официально не поддерживается, но существует форк Orwell Dev-C++, который обновляется по сей день. Установив, я запустил и для пробы написал простую программку, которая отображает текст «Привет, мир!». Но поздороваться она с миром так и не смогла, а лишь сказала что-то непонятное на древнеегипетском. После перелопачивания некоторых форумов и сайтов я нашел множество советов, но основная масса не способна была решить её полностью, образовывались подводные камни о которых расскажу далее.

После написания, компиляции и запуска такой программы:

#include <iostream>

using namespace std;

int main()
{
	cout << "Привет, Мир!"; 
	return 0;
}

Можно получить примерно такой результат

Вывод кракозябр в консоль

Вывод кракозябр в консоль

Сразу понятно, что на приветствие это совсем не похоже.

После прочтения кучи советов стало понятно, что большая часть советов предлагала решить проблему функцией setlocale(), которая находится в заголовочном файле <clocale>.

Последовав совету и усовершенствовав программу таким образом:

#include <iostream>
#include <clocale> //Обязательно для функции setlocale()

using namespace std;

int main()
{
	setlocale(LC_ALL,"Russian"); //Функция setlocale() с аргументами
	cout << "Привет, Мир!";
	return 0;
}

Дополнительно: можно было написать setlocale(0, «») и результат был бы аналогичным, при условии, что в настройках ОС язык системы русский.

На вывод я получил следующий результат

Привет, Мир!

Привет, Мир!

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

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

Коль уж так, я решил вновь внести изменения в программу, пусть она поздоровается со мной по имени.

#include <iostream>
#include <clocale>

using namespace std;

int main()
{
	setlocale(LC_ALL,"Russian");
	char name[12];
	cout << "Введите своё имя: ";
	cin >> name; //Ввод данных
	cout << "Привет, " << name;
	return 0;
}

Но в результате я получил не приветствие

Оскорбление на древнеегипетском?

Оскорбление на древнеегипетском?

Как видно, она не смогла назвать моего имени.

Поискав информацию в сети, я узнал о том, что setlocale() не работает с потокоми ввода/вывода, а то есть с cin,cout,etc. Выходит, что нужно искать альтернативные способы решения данной проблемы, которые предлагались на других сайтах.

Решение проблемы с отображением русских букв в консоли

По-другому решить проблему можно было воспользовавшись функциями SetConsoleCP() и SetConsoleOutputCP() с аргуменом 1251 в обеих. Эти функции требуют подключения заголовка <Windows.h>, практически в каждом компиляторе под Windows он имеется, проблем не будет.

Усовершенствовал программу таким образом

#include <iostream>
#include <Windows.h> // Обязательно для SetConsoleCP() и SetConsoleOutputCP()

using namespace std;

int main()
{
	SetConsoleCP(1251);
	SetConsoleOutputCP(1251);
	char name[12];
	cout << "Введите свое имя: ";
	cin >> name;
	cout << "Привет, " << name;
	return 0;
}

На вывод получил

Вновь кракозябры в консоли

Вновь кракозябры в консоли

Снова что-то непонятное. Но решение, как оказалось, находилось очень близко. У функций SetConsoleCP() и SetConsoleOutputCP() есть небольшой недостаток — они работают только со шрифтом Lucida Console. В консоли же по умолчанию стоит шрифт Consolas, либо точечные шрифты. Следующим этапом сделать нужно вот что. Находясь в консоли нажать кнопку Cmd или нажать на значек программы в левом верхнем углу(Перед D:… в названии), то есть вызвать контекстное меню окна. Далее нажать «Свойства».

Контекстное меню консоли

Контекстное меню консоли

Далее появится окно с настройками, там необходимо выбрать шрифт Lucida Console.

Свойства консоли Windows

Свойства консоли Windows

И нажать на кнопку ОК.

После такой процедуры я вновь запустил программу и…

Работа программы

Работа программы

Да! Она поздоровалась со мной по имени на русском языке.

Данный способ помог решить мне проблему с отображением русских символов в консоли Windows, надеюсь, что кому-нибудь еще он тоже поможет. Спасибо за внимание.

  • Remove From My Forums
  • Question

  • Ну собственно из заголовка думаю все понятно: вместо русских букв выводит иероглифы, с английскими и цифрами никаких проблем. Языковые настройки норме, везде русский, что юникод, что нет.

    Вопрос такой: как можно решить сию проблему без танцев с бубном и дополнительного кода в самой программе? Может какие-то компоненты встали не корректно или чего-то не хватает программе? До этого была
    15 версия, там такого ни разу не было… 

    Заранее благодарен.

Answers

  • #include "stdafx.h"
    
    void main()
    {
    	printf("Тест");
    	printf("Eng");
    }

    Это не будет работать ни в VS2015, ни в VS2013… Читайте про Юникод.

    Проект создаю чисто C++

    printf — функция языка C.

    • Marked as answer by

      Monday, April 24, 2017 10:50 AM

  • Детский вопрос, а Юникодом то пользоваться не пробовали?

    wprintf(L"Тест");

    • Edited by
      VadimTagil
      Sunday, April 23, 2017 5:54 PM
      не та функция
    • Marked as answer by
      Maksim MarinovMicrosoft contingent staff, Moderator
      Monday, April 24, 2017 10:50 AM

  • Следует использовать только 16 битные строки и функции для работы с ними, a так же правильно устанавливать кодировку консоли. Это позволит передавать любые символы Unicode (которые для отображения должны быть в шрифте), даже если они находятся
    в разных кодовых страницах ANSI. При этом все будет работать независимо от настроек ОС. При этом не требуется никаких самопальных «перекодировщиков».

    #include <Windows.h>
    #include <stdio.h>
    #include <tchar.h>
    #include "stdafx.h"
    #include<iostream>
    #include<conio.h>
    #include <iostream>
    #include <io.h>
    #include <fcntl.h>
    
    int _tmain(int argc, _TCHAR* argv[])
    {
            _setmode(_fileno(stdout), _O_U16TEXT);
    	_setmode(_fileno(stdin), _O_U16TEXT);
    
    	SetConsoleCP(1200);
    
    	std::wcout << L"Тебя как зовут? ";
    
    	wchar_t name[81];
    
    	std::wcin >> name;
    
    	std::wcout << name << L", используй Unicode и все будет работать с любыми языками.nr";
    
    	return 0;
    }
    
    
    


    This posting is provided «AS IS» with no warranties, and confers no rights.

    • Marked as answer by
      Maksim MarinovMicrosoft contingent staff, Moderator
      Monday, April 24, 2017 10:50 AM

Alexander, Не важно. Я же написал, что тут еще играет роль кодировка, в которой написаны исходники.
Если исходники написаны в 1251 — то да поможет. Если нет — не поможет.
У некоторых случается такое совпадение, что кодировка исходников и кодировка консоли совпадает и они с такой проблемой не сталкиваются.

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

Кстати, можно действовать и со стороны консоли. Выясняем в какой кодировке у нас исходники и меняем кодировку консоли командой:
chcp 866 — устанавливает в консоли кодировку 866
chcp 1251
chcp 65001 — utf8

Понравилась статья? Поделить с друзьями:
  • Setconfig application обнаружена ошибка windows xp
  • Sniper ghost warrior выдает ошибку
  • Sniper ghost warrior 3 ошибка при установке
  • Sniper ghost warrior 3 ошибка при запуске
  • Sniper elite v2 ошибка 404 при установке