Я читал, что с каждым процессом связан набор переменных локали.
Это не совсем так, или, по крайней мере, он сильно упрощен.
Многие стандартные библиотечные функции (и нестандартные библиотечные функции) изменяют свое поведение, основываясь на наборе конфигураций локали, которые поддерживаются в некотором скрытом глобальном объекте в реализации стандартной библиотеки.(В некоторых реализациях библиотеки конфигурация локали поддерживается для каждого потока, а не глобально, используя локальные статические переменные потока.) Это может показаться связанным с процессом, поскольку обычно у каждого процесса есть один экземпляр времени выполнения стандартной библиотеки,но важно понимать, что, несмотря на внешний вид, поддержка локали является частью библиотеки, а не ядра ОС.(Конечно, ничто в любом стандарте не определяет, где находятся границы ядра, и даже то, каким может быть ядро. Вы можете запустить свою программу «на пустом месте» или у вас может быть ОС, которая считает полезным реализовать стандартную библиотеку в рамках системных вызовов.Я говорю здесь об общих случаях.)
Базовая конфигурация локали определяется стандартом C в разделе 7.11 (стандарта C11), который определяет два интерфейса:
setlocale
, который изменяет конфигурацию локали библиотеки, и
localeconv
, которая запрашивает часть конфигурации локали, позволяя пользовательскому коду соответствоватьк соглашениям о числовом форматировании локали (включая денежное форматирование).
Конфигурация локали разделена на несколько более или менее независимых компонентов, называемых «категориями».(Стандартная библиотека C ++ называет эти «грани», что также является часто используемым словом.) Существует пять категорий, определенных стандартом C, и еще одна, определенная Posix, но категории являются открытыми;отдельные реализации стандартной библиотеки могут свободно добавлять дополнительные категории.Например, стандартная библиотека C Gnu, используемая в большинстве систем Linux, в настоящее время имеет в общей сложности 12 категорий.(Текущий список см. man 7 locale
в вашей системе.)
Стандартные категории:
LC_CTYPE
: классификация символов и преобразование регистра. LC_COLLATE
: порядок сопоставления. LC_MONETARY
: денежное форматирование. LC_NUMERIC
: числовое, неденежное форматирование. LC_TIME
: дата и времяформаты.
и расширение Posix:
LC_MESSAGES
: форматы информационных и диагностических сообщений и интерактивных ответов.
Кроме localeconv
, который предоставляет доступ только к определенным конфигурациям из категорий LC_NUMERIC
и LC_MONETARY
, нет способа запросить какую-либо конкретную конфигурацию.
Также, нет никакого стандартного способа установить единую конфигурацию.Все, что вы можете сделать, это использовать setlocale
для настройки всей категории, используя зависящее от библиотеки и нестандартизированное имя локали (которое является просто символьной строкой).Точнее, стандартизированы два имени локали:
Стандарт C определяет имя локали C
.
Posix определяет имя локали POSIX
.Однако Posix указывает, что соответствующий языковой стандарт должен совпадать с языковым стандартом C
.
Подробности именования языковых стандартов (или должны быть) подробно описаны в документации locale
для среды, в которой вы работаете, но обычно программа с поддержкой локали никогда не вызовет setlocale
со строковой константой, отличной от стандартных имен, или пустой строкой.(Я вернусь к этому через минуту.)
Интерфейс setlocale
позволяет программе устанавливать отдельную категорию языковых стандартов или присваивать всем категориям языковых стандартов одно и то же имя языкового стандарта.Он также возвращает строку, которую можно использовать для возврата к ранее настроенной категории языкового стандарта (или полной конфигурации).
Имена категорий, показанные в списке категорий выше, являются макросами, определенными в <locale.h>
.Дополнительный макрос LC_ALL
также определяется этим заголовочным файлом: LC_ALL
.Один из этих макросов должен использоваться в качестве первого аргумента для setlocale
.
Стандарты C и Posix требуют, чтобы исходный языковой стандарт при запуске программы был языковым стандартом C
.Многие аспекты локали C
стандартизированы (и несколько больше аспектов локали Posix
стандартизированы).Эта стандартизация позволяет программисту предсказать, как будут работать числовые преобразования, например.
Но часто программист захочет взаимодействовать с пользователем программы с собственными настройками языка этого пользователя.Очевидно, что нежелательно, чтобы каждая отдельная программа имела свой собственный уникальный механизм определения предпочтений языкового стандарта пользователя, поэтому стандартная библиотека предоставляет механизм для установки языкового стандарта (или отдельных категорий языковых стандартов) в соответствии с тем, на что настроен языковой стандарт по умолчанию:setlocale
с пустой строкой (""
) в качестве имени локали.Стандарт C не определяет какой-либо конкретный механизм для настройки этой информации;он просто предполагает, что он существует.
(Примечание: вызов setlocale
с пустой строкой в качестве имени локали не такой же, как вызов setlocale
с NULL
в качестве имени локали. NULL
говорит setlocale
не изменять настройку локали, но она все равно возвращает строку, связанную с текущей локалью. Это устраняет необходимость в интерфейсе getlocale
.)
Posix действительно указываетмеханизм настройки пользовательских настроек, и он также настаивает на том, чтобы (большинство) стандартизированных утилит командной строки работали в локали по умолчанию.Этот механизм использует переменные среды, имена которых соответствуют макросам категории setlocale
.
В реализации Posix, когда программа вызывает setlocale(LC_X, "");
, библиотека переходит к проверке текущей среды:
Сначала он ищет переменную окружения LC_ALL
.Если он определен и имеет непустое значение, он используется для определения языкового стандарта.
В противном случае, если первый аргумент setlocale
не был LC_ALL
, он ищетпеременная окружения, имя которой совпадает с этим аргументом.Если он определен и имеет непустое значение, он используется для определения языкового стандарта.
В противном случае, если переменная среды LANG
определена и имеет непустое значение, он используется (некоторым образом, зависящим от реализации) для создания имени локали.(LANG
должен указывать на язык пользователя, который является важной частью их языковых настроек.)
Наконец, используется некоторое общесистемное значение по умолчанию.
Переменные среды обычно инициализируются программой login
(или эквивалентом GUI) на основе файлов конфигурации системы.(Точный механизм варьируется от распределения к распределению, и документацию часто трудно найти.)
Как уже упоминалось, Posix требует, чтобы почти все стандартные утилиты оболочки выполняли эквивалент setlocale(LC_ALL, "");
для работы внастроенный язык пользователя.Страница руководства каждой утилиты (или другая документация) должна указывать, делает ли она это или нет, но разумно предположить, что она делает, если нет какой-либо информации об обратном.
Кроме того, многие (но не все) стандартные библиотекиСтроковые функции ориентированы на локали.Интерфейсы библиотеки, которые определенно не учитывают языковые стандарты, включают isdigit
и isxdigit
, которые всегда отвечают на основе языкового стандарта C
, и strcmp
, который сравнивает строки так же, как memcmp
, используяЗначение char
(интерпретируется как unsigned int
) для определения порядка сортировки.(strcoll
учитывает локаль, если вы хотите сделать сравнение согласно LC_COLLATE
.) А кодировки символов, используемые для широких и многобайтовых символов, управляются (каким-то неуказанным образом) категорией LC_CTYPE
.