Форум программистов, компьютерный форум CyberForum.ru

Различие функций setlocale() и SetConsoleCP()/SetConsoleOutputCP() - C++

Восстановить пароль Регистрация
 
Рейтинг: Рейтинг темы: голосов - 62, средняя оценка - 4.95
xlxndr
 Аватар для xlxndr
56 / 8 / 3
Регистрация: 14.06.2013
Сообщений: 115
20.06.2013, 01:58     Различие функций setlocale() и SetConsoleCP()/SetConsoleOutputCP() #1
Вопрос состоит в следующем... Можно проверить с помощью функций GetACP(), GetOEMCP(), GetConsoleCP(), GetConsoleOutputCP(), что функция setlocale НЕ МЕНЯЕТ НИКАКИХ КОДИРОВОК в потоках ввода/вывода. Однако, если использовать функцию SetConsoleOutputCP(1251) или SetConsoleCP(1251), то после них setlocale() не работает! Особенно удивительно относительно функции SetConsoleCP(1251), она то здесь при чем?!!! Она отвечает только за ввод, но не вывод символов на экран, поэтому портить, по идее, ничего не должна! ?

листинг - 1

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
#include <windows.h>
using namespace std;
 
main()
{
//SetConsoleCP(1251);                //пока отключили
//SetConsoleOutputCP(1251);       //пока отключили
    setlocale(LC_ALL,"Rus");          //Устанавливаем кодировку???
                                
    cout<<GetACP()<<endl;                     //будет - 1251
    cout<<GetOEMCP()<<endl;                 //будет - 866
    cout<<GetConsoleCP()<<endl;            //будет - 866
    cout<<GetConsoleOutputCP()<<endl;   //будет - 866
    
    cout<<"Однако, выводим русские буквы"<<endl;
    cin.get();
}
листинг - 2

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
#include <windows.h>
using namespace std;
 
main()
{
   SetConsoleCP(1251);                  //ВКЛЮЧИЛИ
//SetConsoleOutputCP(1251);       //пока отключили
    setlocale(LC_ALL,"Rus");          //Устанавливаем кодировку???
                                
    cout<<GetACP()<<endl;
    cout<<GetOEMCP()<<endl;
    cout<<GetConsoleCP()<<endl;                     //поменялась
    cout<<GetConsoleOutputCP()<<endl;  
    
    cout<<"Получили крокозябры, хотя в ВЫВОДЕ на консоль НИЧЕГО не меняли"<<endl;
    cin.get();
}
листинг-3

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
#include <windows.h>
using namespace std;
 
main()
{
    //SetConsoleCP(1251);                //пока отключили
      SetConsoleOutputCP(1251);         //ВКЛЮЧИЛИ
      setlocale(LC_ALL,"Rus");          //Устанавливаем кодировку???
                                
    cout<<GetACP()<<endl;
    cout<<GetOEMCP()<<endl;
    cout<<GetConsoleCP()<<endl;                
    cout<<GetConsoleOutputCP()<<endl;    //поменялась
    
    cout<<"Опять получили крокозябры, хотя в ВЫВОДЕ на консоль русская кодировка 1251"<<endl;
    cin.get();
}
Но вот если использовать SetConsoleOutputCP(866) или SetConsoleCP(866), то все работает нормально... Почему? Получается, если просто использовать SetConsoleOutputCP(1251) или SetConsoleCP(1251), то указываем русскую кодировку, а если setlocale, то кодировка консоли - и вывода, и что удивительно, даже ВВОДА, должно быть CP866.
Во-первых, почему CP866? Во-вторых, при чем тут функция изменения ввода SetConsoleCP(866), если мы ничего не вводим?
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
20.06.2013, 01:58     Различие функций setlocale() и SetConsoleCP()/SetConsoleOutputCP()
Посмотрите здесь:

C++ setlocale
Setlocale vs. SetConsoleCP C++
Setlocale C++
C++ Setlocale() и getline()
C++ Setlocale в wmain()
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
MrGluck
Ворчун
Эксперт С++
 Аватар для MrGluck
4919 / 2662 / 243
Регистрация: 29.11.2010
Сообщений: 7,398
20.06.2013, 02:11     Различие функций setlocale() и SetConsoleCP()/SetConsoleOutputCP() #2
Вам не понять всю любовь и идеологию шиндоуз, особенно по части кодировок.

Если указываем кодировку 1251, то необходимо выбрать в свойствах консоли шрифт Lucida Console.
setlocale - стандартная функция, SetConsoleOutputCP() - проприетарная. Что в ней самой творится один microsoft знает, вполне вероятно, что он вставляет палки в колеса работе функции setlocale(). Не за чем вам мешать просто две эти функции. Остановитесь на чем-то одном и радуйтесь.
xlxndr
 Аватар для xlxndr
56 / 8 / 3
Регистрация: 14.06.2013
Сообщений: 115
20.06.2013, 15:33  [ТС]     Различие функций setlocale() и SetConsoleCP()/SetConsoleOutputCP() #3
Как раз и хочется понять, куда вставвляются палки... Чтобы понять механизм работы функций setlocale() и SetConsoleOutputCP()
Про Lucida Console - понятно, но это здесь не причем...

Добавлено через 17 минут
Единственный вывод, который напрашивается - это что setlocale() ПЕРЕВОДИТ текст из редактора кода в указанную кодировку перед выводом на консоль или в файл, но НЕ МЕНЯЕТ кодировку самой консоли или другого интерфейса... Поэтому при изменении кодировки консоли на 1251 текст оказывается уже переведенным в кодировку 866, и получаются крокозябры... Значит, нужно установить кодировку консоли - тоже 866... Но setlocale() работает только с выводом текста, поэтому при вводе по-любому, придется использовать SetConsoleOutputCP(1251).

Однако, тогда остается не понятным, как может портить ВЫВОД на консоль функция изменения кодировки ВВОДА - SetConsoleCP()?...

Добавлено через 13 часов 1 минуту
В общем, методом экспериментов можно сделать такой вывод:
1. SetConsoleOutputCP() устанавливает кодировку ВЫВОДА на консоль
2. SetConsoleCP() устанавливает кодировку ВВОДА из консоли И ИЗ РЕДАКТОРА КОДА
3. setlocale(LC_ALL,"1251") проверяет, какая кодировка установлена сейчас, и если она не 1251, то меняет ее на 1251, а если уже 1251, то ничего не делает.
Поэтому, если уже установлена кодировка ввода ИЗ РЕДАКТОРА функцией SetConsoleCP(1251), то после нее setlocale() ничего менять не будет, и попросту выведет символы по нумерации CP866, решив, что они и так уже в windows 1251.
Если же уже выполнена функция SetConsoleOutputCP(1251), то setlocale() проверит, какая кодировка ввода установлена, и обнаружит, что кодировка ввода по прежнему CP866, поэтому она возьмет номера этих уже преобразованных символов (с помощью SetConsoleOutputCP(1251)), НО ИЗ кодовой таблицы cp866 и выведет символы с этими номерами из таблицы windows 1251.
alsav22
5282 / 4801 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
20.06.2013, 16:11     Различие функций setlocale() и SetConsoleCP()/SetConsoleOutputCP() #4
Цитата Сообщение от MrGluck Посмотреть сообщение
Не за чем вам мешать просто две эти функции.
Иногда приходится мешать. Например, если нужно обрабатывать ввод русских букв с помощью функций cctype.
Вот такой код, при вводе русских букв, не будет работать как надо:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
#include <cstdlib>
#include <cctype>
#include <Windows.h>
using namespace std; 
 
int main()
{
   
   //setlocale(LC_ALL,"Rus");
   SetConsoleCP(1251);                
   SetConsoleOutputCP(1251);
 
   char ch;
   cin >> ch;
   if (isalpha((unsigned char)ch)) cout << "is alpha" << endl;
   else cout << "no alpha" << endl;
 
   system("pause");
   return 0;
}
Если раскоментировать, то будет.
Yandex
Объявления
20.06.2013, 16:11     Различие функций setlocale() и SetConsoleCP()/SetConsoleOutputCP()
Ответ Создать тему
Опции темы

Текущее время: 06:42. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru