, сведения о локали не изменяются. Вместо этого функция возвращает строку, представляющую текущую локаль для данной категории.
Поскольку каждая категория может быть установлена индивидуально, автор приложения решает, насколько будет программа использовать локаль. Например, если
main
делает лишь это —
setlocale(LC_TIME, "");
/* Использование локали только для времени и все */
— тогда, независимо от установленных в окружении других переменных
LC_xxx
,
локали подчиняются лишь функции времени и даты. Все остальные действуют так, как если бы программа по-прежнему работала в локали «С». Сходным образом вызов:
setlocale(LC_TIME, "it_IT"); /* Время всегда итальянское */
заменяет переменную окружения
LC_TIME
(также, как
LC_ALL
), заставляя программу использовать для вычислений времени/даты данные для Италии. (Хотя Италия может быть прекрасным местом, программам лучше использовать
""
, чтобы они могли корректно работать везде; этот пример предназначен лишь для объяснения того, как работает
setlocale
.)
Можно индивидуально вызывать
setlocale
для каждой категории, но простейшим способом является установка всего одним махом:
/* Находясь в Риме, вместо «всего» делайте все как римляне. :-) */
setlocale(LC_ALL, "");
Возвращаемое
setlocale
значение является текущей установкой локали. Это либо строковое значение, переданное в предыдущем вызове, либо непрозрачное значение, представляющее используемую вначале локаль. Это самое значение может быть затем передано обратно
setlocale
. Для последующего использования возвращаемое значение должно быть скопировано в локальное хранилище, поскольку это указатель на внутренние данные.
char *initial_locale;
initial_locale = strdup(setlocale(LC_ALL, "")); /* сохранить копию */
...
(void)setlocale(LC_ALL, initial_locale); /* восстановить ее */
Здесь мы сохранили копию, использовав функцию POSIX
strdup
(см. раздел 3.2.2 «Копирование строк:
strdup
»).
13.2.3. Сравнение строк:
strcoll
и
strxfrm
Знакомая функция
strcmp
сравнивает две строки, возвращая отрицательное, нулевое или положительное значения, если первая строка меньше, равна или больше второй. Это сравнение основано на числовых значениях символов в машинном наборе символов. Из-за этого результаты
strcmp
никогда не изменяются.
Однако, при наличии локалей простого числового сравнения недостаточно. Каждая локаль определяет для содержащихся в ней символов последовательность сортировки, другими словами, относительный порядок символов внутри локали. Например, в простом 7-битном ASCII у двух символов '
А
' и '
а
' десятичные значения равны 65 и 97 соответственно. Соответственно, во фрагменте
int i = strcmp("А", "a");
i
имеет отрицательное значение. Однако, в локали "
en_US.UTF-8
" '
A
' идет после '
a
', а не перед ним. Таким образом, использование
strcmp
для
приложений, использующих локаль, является плохой мыслью, мы могли бы сказать, что она возвращает игнорирующий локаль ответ.
Функция
strcoll
(string collate — сортировка строк) существует для сравнения строк с использованием локали:
#include <string.h> /* ISO С */
int strcoll(const char *s1, const char *s2);
Она возвращает такие же отрицательные/нулевые/положительные значения, что и
strcmp
. Следующая программа,
ch13-compare.c
, интерактивно демонстрирует разницу:
1 /* ch13-compare.с --- демонстрация strcmp против strcoll */
2
3 #include <stdio.h>
4 #include <locale.h>
5 #include <string.h>
6
7 int main(void)
8 {
9 #define STRBUFSIZE 1024
10 char locale[STRBUFSIZE], curloc[STRBUFSIZE];
11 char left[STRBUFSIZE], right[STRBUFSIZE];
12 char buf[BUFSIZ];
13 int count;
14
15 setlocale(LC_ALL, ""); /* установить локаль */
16 strcpy(curloc, setlocale(LC_ALL, NULL)); /* сохранить ее */
17
18 printf("--> "); fflush(stdout);
19 while (fgets(buf, sizeof buf, stdin) != NULL) {
30 printf("%s: strcmp(\"%s\", \"%s\") is %d\n", curloc, left,
31 right, strcmp(left, right));
32 printf("%s: strcoll(\"%s\", \"%s\") is %d\n", curloc, left,
33 right, strcoll(left, right));
34
35 printf("\n--> "); fflush(stdout);
36 }
37
38 exit(0);
39 }
Программа читает входные строки, состоящие из двух сравниваемых слов и необязательной локали, использующейся для сравнения. Если локаль дана, она становится локалью для последующих элементов. Программа начинает с любой локалью, которая установлена в окружении.
Массив
curloc
сохраняет текущую локаль для вывода результатов;
left
и
right
являются левым и правым сравниваемыми словами (строки 10–11). Основную часть программы составляет цикл (строки 19–36), который читает строки и выполняет работу. Строки 20–23 разделяют входную строку,
locale
инициализируется пустой строкой, если третья строка не предусмотрена.