Широкие символы могут быть от 16 до 32 битов размером в зависимости от реализации. Как упоминалось, они нацелены на манипулирование данными в памяти и обычно не хранятся в файлах непосредственно.
Стандарт C предусматривает для широких символов большое число функций и макросов, соответствующих традиционным функциям, работающим с данными char. Например, wprintf(), iswlower() и т.д. Они документированы в справочных страницах GNU/Linux и в книгах по стандартному С.
13.4.2. Представления многобайтных символов
Строки широких символов сохраняются на диске путем преобразования их в памяти в многобайтное представление набора символов с последующей записью в дисковый файл. Сходным образом, такие строки считываются с диска через низкоуровневый блочный ввод/вывод, а затем конвертируются в памяти из многобайтной версии в версию широких символов.
Многие описанные кодировки используют для представления многобайтных символов состояния регистра (shift states). Другими словами, в данном потоке байтов значения байтов представляют самих себя до тех пор, пока не встретится специальное управляющее значение. В этот момент интерпретация изменяется в соответствии с текущим состоянием регистра. Таким образом, одно и то же восьмибитовое значение может иметь два значения: одно для обычного состояния, без использования регистра, и другое для использования регистра. Предполагается, что правильно закодированные строки начинаются и заканчиваются с одним и тем же состоянием регистра.
Значительным преимуществом Unicode является то, что его представления являются самокорректирующимися; кодировки не используют состояния регистров, поэтому потеря данных в середине не может повредить последующим закодированным данным.
Первоначальные версии функций преобразования многобайтных символов в широкие и широких в многобайтные поддерживали закрытую копию состояния преобразования (например, состояние регистра, а также все остальное, что могло понадобиться) Такая модель ограничивает использование функции лишь одним видом преобразования в течение жизни программы. Примерами являются mblen() (определение длины многобайтной строки), mbtowc() (преобразование многобайтного символа в широкий), wctomb() (преобразование широкого символа в многобайтный), mbstowcs() (преобразование многобайтной строки в строку широких символов), wcstombs() (преобразование строки широких символов в многобайтную строку).
Новые версии этих процедур называются повторно запускаемыми (restartable). Это означает, что код уровня пользователя сохраняет состояние преобразования в отдельном объекте типа mbstate_t. Соответствующими примерами являются mbrlen(), mbrtowc(), wcrtomb(), mbsrtowcs() и wcsrtombs(). (Обратите внимание на r в их именах, это означает «restartable».)
13.4.3. Языки
Языковые проблемы управляются локалью. Ранее в главе мы уже видели setlocale() POSIX предоставляет продуманный механизм для определения правил, посредством которых работает локаль; некоторые подробности см. в справочной странице GNU/Linux locale(5), а полностью — в самом стандарте POSIX.
Правда в том, что подробности на самом деле не нужны. Вам, как разработчику программ, не нужно беспокоиться о них; как заставить все работать, зависит от разработчиков библиотек. Все, что нужно, это понять концепции и использовать в своем коде соответствующие функции, такие, как strcoll() (см. раздел 13.2.3 «Сравнение строк: strcoll() и strxfrm()»).
Современные системы GLIBC предоставляют отличную поддержку локалей, включая поддерживающие локали процедуры сопоставления регулярных выражений. Например, расширенное регулярное выражение POSIX [[:alpha:]][[:alnum:]]+ соответствует букве, за которой следуют одна или более букв или цифр (алфавитный символ, за которым следуют один или более алфавитно-цифровых символов). Определение того, какие символы соответствуют этим классам, зависит от локали. Например, это регулярное выражение соответствовало бы двум символам 'eè', тогда как регулярное выражение [a-zA-Z][a-A-Zz0-9]+ традиционного, ориентированного на ASCII Unix — скорее всего нет. Классы символов POSIX перечислены в табл. 13.5.
Таблица 13.5. Классы символов регулярных выражений POSIX
| Класс | Соответствует |
|---|---|
[:alnum:] |
Алфавитно-цифровые символы |
[:alpha:] |
Алфавитные символы |
[:blank:] |
Символы пробела и табуляции. |
[:cntrclass="underline" ] |
Управляющие символы |
[:digit:] |
Цифровые символы |
[:graph:] |
Символы, являющиеся одновременно печатными и видимыми. (Символ конца строки печатный, но не видимый, тогда как $ является и тем, и другим.) |
[:lower:] |
Строчные алфавитные символы |
[:print:] |
Печатные (не управляющие) символы |
[:punct:] |
Знаки пунктуации (не буквы, цифры, управляющие или пробельные символы) |
[:space:] |
Пробельные символы (такие, как сам пробел, символы табуляции, конца строки и т.д) |
[:upper:] |
Заглавные алфавитные символы |
[:xdigit:] |
Символы из набора abcdefABCDEF0123456789 |
13.4.4. Заключение
Возможно, вам никогда не придется иметь дело с различными наборами символов и их представлениями. С другой стороны, мир быстро становится «глобальным сообществом», и авторы программ не могут позволить себе быть ограниченными. Следовательно, стоит знать о проблемах интернационализации и наборов символов, а также способах их влияния на поведение вашей системы. По крайней мере, уже один из поставщиков дистрибутивов GNU/Linux устанавливает для систем в Соединенных Штатах локаль по умолчанию en_US.UTF-8.