2016-11-09 16 views
3

Моя установка: glibc 2.24, gcc 6.2.0, среда UTF-8.Почему функции wctype.h не работают без setlocale()?

Рассмотрим следующий пример:

#include <wchar.h> 
#include <wctype.h> 
#include <locale.h> 
int main(void) 
{ 
    setlocale(LC_CTYPE, "en_US.UTF-8"); 
    wchar_t wc = L'я'; /* 00000100 01001111 */ 
    if (iswlower(wc)) return 0; 
    return 1; 
} 

компилировать и запустить его:

$ gcc test.c 
$ ./a.out; echo $? 
0 

Теперь удалить setlocale() и запустить снова. Результат отличается:

$ gcc test.c 
$ ./a.out; echo $? 
1 

Технически setlocale() здесь не требуется, так как функции от wctype.h работы с широкими символами, которые имеют фиксированную кодировку. (Само собой разумеется, что setlocale() требуется, если мы хотим, чтобы функции от ctype.h работали корректно с символами, отличными от ASCII, и если мы используем функции преобразования символов из wchar.h - для установки внешней кодировки.)

Почему пример не работает Работа без setlocale()?

+1

Как еще он узнает, какой алфавит использовать? –

+0

@ IgnacioVazquez-Abrams ISO10646 - он фиксируется для широких символов. https://www.gnu.org/software/libc/manual/html_node/Extended-Char-Intro.html –

+0

ISO 10646 не называет алфавита. –

ответ

1

Стандарт C говорит:

7.25 Широкий характер классификации и картографирования утилиты <wctype.h>

...

Поведение этих функций зависит от LC_CTYPE категории текущей локали.

Кроме того (5.2.1 Наборы символов)

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

, а затем (7,19 Общие определения <stddef.h>)

wchar_t , который представляет собой целое число, чей тип диапазон значений может представлять различные коды для всех членов наибольшего расширенного набора символов, указанных в списке поддерживаемых локалей

Таким образом, может быть много расширенных наборов символов, по одному для каждого языкового стандарта. Таким образом, кодирование wchar_t может быть зависимым от языка, поскольку кодирование представляет собой сопоставление между набором целых кодов и набором символов, а второе - зависящим от языка.

Учитывая вышеуказанное, <wctype.h>должен быть зависимым от региона.В противном случае стандарт должен был бы указать, что существует единый независимый набор символов.

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

Что касается специфического поведения gcc и glibc, они всегда используют Unicode/ISO10646/UCS4 в качестве расширенного набора символов для простоты в любой локали. Однако они не классифицируют расширенные символы в соответствии со стандартом языка C, потому что они не должны, как это допускает стандарт. (Далее следует дикая догадка). Полные таблицы классификации Юникода большие, и программам, которые нужны только ASCII, не нужно платить за их использование.

+0

Я пытаюсь понять обоснование стандарта. Если не указано, locale - '' C "'. Итак, если 'setlocale()' удаляется из примера в OP, он должен работать в любом случае, но это не так. Что мешает '' C '' наследовать от 'i18n', а' 'en_US' 'наследует от' i18n'? (см. комментарий IgnacioVazquez-Abrams к OP) –

+0

@IgorLiferenko см. обновление –