Настройка локали

При изменении регистра русских букв может возникнуть проблема. Чтобы ее избежать, необходимо правильно настроить локаль (совокупность локальных настроек системы).

Настройка локали в языке C

Для настройки локали используется функция setlocale(). Прототип функции:

#include <clocale> /* или #include <locale.h> */
char *setlocale(int category, const char *locale);

В первом параметре указывается категория в виде числа от 0 до 5 или соответствующий числу макрос:

  • 0 — LC_ALL — устанавливает локаль для всех категорий;
  • 1 — LC_COLLATE — для сравнения строк;
  • 2 — LC_CTYPE — для перевода символов в нижний или верхний регистр;
  • 3 — LC_MONETARY — для отображения денежных единиц;
  • 4 — LC_NUMERIC — для форматирования дробных чисел;
  • 5 — LC_TIME — для форматирования вывода даты и времени.

Во втором параметре задается название локали в виде строки, например: rus, russian или Russian_Russia. В этом случае будет задана кодировка, используемая в системе по умолчанию:

char *pLocale = std::setlocale(LC_ALL, "Russian_Russia");
if (pLocale) {
   std::cout << pLocale << std::endl; // Russian_Russia.1251
}
else std::cout << "Не удалось настроить локаль" << std::endl;

Чтобы использовать другую кодировку нужно указать ее название после точки, например, ".1251" или "Russian_Russia.1251":

char *pLocale = std::setlocale(LC_ALL, "Russian_Russia.1251");
if (pLocale) {
   std::cout << pLocale << std::endl; // Russian_Russia.1251
}
else std::cout << "Не удалось настроить локаль" << std::endl;

Вместо названия можно указать пустую строку. В этом случае будет использоваться локаль, настроенная в системе:

char *pLocale = std::setlocale(LC_ALL, "");
if (pLocale) {
   std::cout << pLocale << std::endl; // Russian_Russia.1251
}

В качестве значения функция возвращает указатель на строку с названием локали, соответствующей заданной категории, или нулевой указатель в случае ошибки. Если во втором параметре передан нулевой указатель, то функция возвращает указатель на строку с названием текущей локали:

char *pLocale = std::setlocale(LC_ALL, nullptr);
if (pLocale) {
   std::cout << pLocale << std::endl; // C
}

Для настройки локали можно также использовать функцию _wsetlocale(). Прототип функции:

#include <cwchar> /* или #include <wchar.h> */
wchar_t *_wsetlocale(int category, const wchar_t *locale);

Параметры аналогичны одноименным параметрам функции setlocale(), но во втором параметре указывается L-строка с названием локали и возвращается указатель на L-строку:

wchar_t *pLocale = _wsetlocale(LC_ALL, L"Russian_Russia.1251");
if (pLocale) {
   std::wcout << pLocale << std::endl; // Russian_Russia.1251
}

После настройки локали многие функции будут работать не так как раньше. Например, от настроек локали зависит вывод функции printf():

std::printf("%.2f\n", 2.5);            // 2.50
std::setlocale(LC_NUMERIC, "dutch");
std::printf("%.2f\n", 2.5);            // 2,50

Некоторые функции позволяют указать локаль в качестве параметра, например, функция _printf_l():

int _printf_l(const char *format, _locale_t locale, ...);

Во втором параметре функция принимает структуру _locale_t с настройками локали. Создать эту структуру позволяет функция _create_locale(). Прототип функции:

#include <clocale> /* или #include <locale.h> */
_locale_t _create_locale(int category, const char *locale);

Все параметры аналогичны одноименным параметрам функции setlocale(). Если структуру создать не удалось, то функция возвращает нулевой указатель.

Создать структуру _locale_t с настройками текущей локали позволяет функция _get_current_locale(). Прототип функции:

#include <clocale> /* или #include <locale.h> */
_locale_t _get_current_locale(void);

Когда структура больше не нужна, ее следует освободить с помощью функции _free_locale(). Прототип функции:

#include <clocale> /* или #include <locale.h> */
void _free_locale(_locale_t locale);

Пример настройки локали и вывода текущего названия локали приведен в листинге 7.1.

Листинг 7.1. Настройка локали

#include <iostream>
#include <clocale>

int main() {
   char *pLocale = std::setlocale(LC_ALL, NULL);
   if (pLocale) {
      std::cout << pLocale << std::endl; // C
   }
   std::printf("%.2f\n", 3.14);          // 3.14
   pLocale = std::setlocale(LC_NUMERIC, "dutch");
   if (pLocale) {
      std::cout << pLocale << std::endl; // Dutch_Netherlands.1252
   }
   std::printf("%.2f\n", 3.14);          // 3,14
   pLocale = std::setlocale(LC_ALL, "Russian_Russia");
   if (pLocale) {
      std::cout << pLocale << std::endl; // Russian_Russia.1251
   }
   pLocale = std::setlocale(LC_ALL, "Russian_Russia.866");
   if (pLocale) {
      std::cout << pLocale << std::endl; // Russian_Russia.866
   }

   _locale_t locale_c = _create_locale(LC_NUMERIC, "C");
   _printf_l("%.2f\n", locale_c, 3.14);  // 3.14
   _free_locale(locale_c);
   _locale_t locale_de = _create_locale(LC_NUMERIC, "dutch");
   _printf_l("%.2f\n", locale_de, 3.14); // 3,14
   _free_locale(locale_de);
   return 0;
}

Функция localeconv() позволяет получить информацию о способе форматирования вещественных чисел и денежных сумм для текущей локали. Прототип функции:

#include <clocale> /* или #include <locale.h> */
struct lconv *localeconv(void);

Функция возвращает указатель на структуру lconv. Пример вывода символа десятичного разделителя для локали Russian_Russia.1251:

std::setlocale(LC_ALL, "Russian_Russia.1251");
lconv *p = std::localeconv();
if (p) {
   std::cout << p->decimal_point << std::endl;
}

Объявление структуры lconv выглядит следующим образом:

struct lconv {
   char *decimal_point;     // Десятичный разделитель (",")
   char *thousands_sep;     // Разделитель тысяч (" ")
   char *grouping;          // Способ группировки значений
   char *int_curr_symbol;   // Название валюты ("RUR")
   char *currency_symbol;   // Символ валюты ("р.")
   char *mon_decimal_point; // Десятичный разделитель для 
                            // денежных сумм (",")
   char *mon_thousands_sep; // Разделитель тысяч для денежных
                            // сумм (" ")
   char *mon_grouping;   // Способ группировки для денежных сумм
   char *positive_sign;  // Положительный знак для денежных сумм
   char *negative_sign;  // Отрицательный знак для денежных сумм ("-")
   char int_frac_digits; // Количество цифр в дробной части для 
                         // денежных сумм в международном формате (2)
   char frac_digits;     // Количество цифр в дробной части для
                         // денежных сумм в национальном формате (2)
   char p_cs_precedes;   // 1 - если символ валюты перед значением
                         // 0 - если символ валюты после значения
   char p_sep_by_space;  // 1 - если символ валюты отделяется пробелом
                         // 0 - в противном случае
                         // p_cs_precedes и p_sep_by_space применяются
                         // для положительных значений
   char n_cs_precedes;   // 1 - если символ валюты перед значением
                         // 0 - если символ валюты после значения
   char n_sep_by_space;  // 1 - если символ валюты отделяется пробелом
                         // 0 - в противном случае
                         // n_cs_precedes и n_sep_by_space применяются
                         // для отрицательных значений
   char p_sign_posn;     // Позиция символа положительного значения
   char n_sign_posn;     // Позиция символа отрицательного значения
};

В VC++ доступны также следующие поля структуры lconv:

wchar_t *_W_decimal_point;
wchar_t *_W_thousands_sep;
wchar_t *_W_int_curr_symbol;
wchar_t *_W_currency_symbol;
wchar_t *_W_mon_decimal_point;
wchar_t *_W_mon_thousands_sep;
wchar_t *_W_positive_sign;
wchar_t *_W_negative_sign;

Учебник C++ (MinGW-W64)
Учебник C++ (MinGW-W64) в формате PDF

Помощь сайту

ЮMoney (Yandex-деньги): 410011140483022

ПАО Сбербанк:
Счет: 40817810855006152256
Реквизиты банка:
Наименование: СЕВЕРО-ЗАПАДНЫЙ БАНК ПАО СБЕРБАНК
Корреспондентский счет: 30101810500000000653
БИК: 044030653
КПП: 784243001
ОКПО: 09171401
ОКОНХ: 96130
Скриншот реквизитов