Программирование на C: Как программировать для Unicode?

\?? - это каталог виртуальных объектов ядра, в котором диспетчер объектов ищет локальные и глобальные символические ссылки устройства DOS. Сначала он проверяет локальные ссылки на устройства DOS для сеанса входа пользователя в \Sessions\0\DosDevices\[Logon_AuthenticationId]. Затем он проверяет ссылки на глобальные устройства DOS в \Global??. Еще в старые времена NT использовал один каталог \DosDevices. В настоящее время \DosDevices является ссылкой на \??. Кроме того, в каждом локальном каталоге устройств DOS есть ссылка «Глобальная», чтобы разрешить доступ к глобальным устройствам, когда локальное устройство затеняет глобальное (например, \\?\Global\Z:) или разрешить драйверу устройства создавать глобальное устройство, если оно не выполняется в системе нить.

В пользовательском режиме библиотека времени выполнения в файле ntdll.dll преобразует полностью определенный путь DOS / Windows к пути NT путем добавления \??\ для буквы диска или замены ведущего \\ Путь UNC с \??\UNC\ - за исключением путей \\?\ и \\.\ локального устройства просто заменяется на \??\. Но сначала путь устройства \\.\ претерпевает некоторую предварительную обработку, например, разрешение «.». и "..", тогда как \\?\ обходит все предварительную обработку пользовательского режима.

Например, обычно \\?\C:\Windows преобразуется в \??\C:\Windows, который разрешает \Global??\C:\Windows. Устройство DOS с буквой «C:» является символической ссылкой на устройство громкости NT. Конечная цель зависит от системы. Например, конечный путь NT может разрешить \Device\HarddiskVolume2\Windows.

Соединения устройств DOS, такие как Volume{00000000-0000-0000-0000-000000000000}, создаются диспетчером точки монтирования. Это клей между постоянными буквами дисков, точками монтирования NTFS и используемым в данный момент устройством тома NT, например \Device\HarddiskVolume2.

80
задан Jonathan Leffler 9 February 2009 в 05:53
поделиться

7 ответов

Обратите внимание, что это не о "строгом unicode, программирующем" по сути, но некотором практическом опыте.

то, Что мы сделали в моей компании, должно было создать библиотеку-оболочку вокруг библиотеки ICU IBM. Библиотека-оболочка имеет интерфейс UTF-8 и преобразовывает в UTF-16, когда необходимо назвать ICU. В нашем случае мы не волновались слишком много о хитах производительности. Когда производительность была проблемой, мы также предоставили интерфейсы UTF-16 (использующий наш собственный тип данных).

Приложения могли остаться в основном как есть (использующий символ), хотя в некоторых случаях они должны знать об определенных вопросах. Например, вместо strncpy () мы используем обертку, которая старается не отключать последовательности UTF-8. В нашем случае это достаточно, но можно было также рассмотреть проверки на комбинированные символы. У нас также есть обертки для подсчета количества кодовых точек, количества графем, и т.д.

При взаимодействии через интерфейс с другими системами, мы иногда должны делать пользовательский символьный состав, таким образом, Вам, возможно, понадобится некоторая гибкость там (в зависимости от Вашего приложения).

Мы не используем wchar_t. Используя ICU избегает неожиданных проблем в мобильности (но не другие неожиданные проблемы, конечно, :-).

21
ответ дан Hans van Eck 9 February 2009 в 05:53
поделиться

Этот FAQ является богатством информации Между той страницей и эта статья Joel Spolsky , у Вас будет хорошее начало.

Одно заключение я приехал в по пути:

  • wchar_t 16 битов в Windows, но не обязательно 16 битов на других платформах. Я думаю, что это - необходимое зло в Windows, но вероятно может избежаться в другом месте. Причина это важно в Windows, состоит в том, что Вам нужен он для использования файлов, которые имеют символы неASCII на имя (наряду с версией W функций).

  • Примечание, что Windows APIs, которые берут wchar_t строки, ожидает кодировку UTF-16. Обратите внимание также, что это отличается, чем UCS-2. Примите во внимание суррогатные пары. Этот тестовая страница имеет поучительные тесты.

  • , Если Вы программируете в Windows, Вы не можете использовать fopen(), fread(), fwrite(), и т.д. так как они только берут char * и не понимают кодировки UTF-8. Делает мобильность болезненной.

10
ответ дан Gaurang Tandon 9 February 2009 в 05:53
поделиться
  • 1
    Это работало. Попытка состояла в том, чтобы добавить виртуальное устройство Galaxy Nexus. Измененный от 1024 - 512 МБ по умолчанию. Ничто иное не изменилось. – Dombey 25 January 2014 в 16:00

Сделать строгое программирование Unicode:

  • Только строковые API использования, которые являются знающим Unicode ( НЕ strlen, strcpy... но их widestring дубликаты wstrlen, wsstrcpy...)
  • При контакте с блоком текста, используют кодирование, которое позволяет хранить символы Unicode (utf-7, utf-8, utf-16, ucs-2...) без потери.
  • Проверка, что Ваш набор символов значения по умолчанию ОС является совместимым Unicode (исключая: utf-8)
  • шрифты Использования, которые являются совместимым Unicode (например, arial_unicode)

Многобайтовый символ, упорядочивают, кодирование, которое предшествует кодировке UTF-16 (тот, используемый обычно с wchar_t), и это кажется мне, это довольно только для Windows.

я никогда не слышал о wint_t.

7
ответ дан approxiblue 9 February 2009 в 05:53
поделиться

Вы в основном хотите иметь дело со строками в памяти как wchar_t массивы вместо символа. Когда Вы делаете любой вид ввода-вывода (как чтение/запись файлов), можно кодировать/декодировать использование UTF-8 (это - вероятно, наиболее распространенное кодирование), который достаточно прост реализовать. Просто погуглите RFCs. Таким образом в оперативной памяти ничто не должно быть многобайтовым. Один wchar_t представляет один символ. Когда Вы приходите к сериализации однако, именно тогда необходимо закодировать к чему-то как UTF-8, где некоторые символы представлены несколькими байтами.

необходимо будет также записать новые версии strcmp и т.д. для строк широкого символа, но это не большая проблема. Самой большой проблемой будет interop с кодом библиотек / существующим кодом, которые только принимают массивы символов.

И когда дело доходит до sizeof (wchar_t) (Вам будут нужны 4 байта, если Вы захотите сделать его правильно) можно всегда переопределять его к большему размеру со взломами определения типа/макроса, если Вы должны.

2
ответ дан Mike Weller 9 February 2009 в 05:53
поделиться
  • 1
    Вы can' t осуществляют корректную обработку, просто звоня strtotime. Например, кто-то мог передвинуть месяц и день, и strtotime не обработает его. – Billy ONeal 3 May 2010 в 07:06

C99 или ранее

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

, Следовательно, подход, предложенный Hans van Eck (который должен записать обертку вокруг ICU - Международных Компонентов для Unicode - библиотека), является звуковым, IMO.

кодировка UTF-8 имеет много достоинств, одно из которых - то, что, если Вы не смешиваете с данными (путем усечения ее, например), затем она может быть скопирована функциями, которые не полностью осведомлены о запутанности кодировки UTF-8. Это - категорически не случай с wchar_t.

Unicode полностью является 21-разрядным форматом. Таким образом, Unicode резервирует кодовые точки от U+0000 до U+10FFFF.

Одна из полезных вещей о UTF-8, UTF-16 и форматы UTF-32 (где UTF обозначает Формат преобразования Unicode - видят Unicode) - то, что можно преобразовать между этими тремя представлениями без потери информации. Каждый может представить что-либо, что другие могут представить. И UTF-8 и UTF-16 являются многобайтовыми форматами.

UTF-8 известен быть многобайтовым форматом с осторожной структурой, которая позволяет найти запуск символов в строке надежно, запускающийся в любой точке в строке. Однобайтовые символы имеют высоко-разрядный набор для обнуления. Многобайтовые символы имеют первый символ, запускающийся с одной из комбинаций двоичных разрядов 110, 1110 или 11110 (для 2 байтов, 3-байтовых или 4-байтовых символов), с последующими байтами, всегда запускающимися 10. Символы продолжения всегда находятся в диапазоне 0x80.. 0xBF. Существуют правила, что символы UTF-8 должны быть представлены в минимальном возможном формате. Одно последствие этих правил то, что байты 0xC0 и 0xC1 (также 0xF5.. 0xFF), не может появиться в допустимых данных UTF-8.

 U+0000 ..   U+007F  1 byte   0xxx xxxx
 U+0080 ..   U+07FF  2 bytes  110x xxxx   10xx xxxx
 U+0800 ..   U+FFFF  3 bytes  1110 xxxx   10xx xxxx   10xx xxxx
U+10000 .. U+10FFFF  4 bytes  1111 0xxx   10xx xxxx   10xx xxxx   10xx xxxx

Первоначально, надеялись, что Unicode будет набором 16-битного кода, и все вписалось бы в пространство 16-битного кода. К сожалению, реальный мир более сложен, и он должен был быть расширен до текущего 21-разрядного кодирования.

UTF-16 таким образом является единым блоком (16-разрядное слово) кодовый набор для 'Основной Многоязычной Плоскости', означая символы с кодовыми точками Unicode U+0000.. U+FFFF, но использование две единицы (32 бита) для символов вне этого диапазона. Таким образом код, который работает с кодировкой UTF-16, должен смочь обработать кодировку переменной ширины, точно так же, как UTF-8 должен. Коды для символов двойной единицы называют суррогатами.

Суррогаты являются кодовыми точками от двух специальных диапазонов значений Unicode, зарезервированных для использования в качестве продвижения и запаздывающих значений парных элементов кода в UTF-16. Продвижение, также названный высоко, суррогаты от U+D800 до U+DBFF и запаздывания, или низко, суррогаты от U+DC00 до U+DFFF. Их называют суррогатами, так как они не представляют символы непосредственно, но только как пара.

UTF-32, конечно, может закодировать любую кодовую точку Unicode в едином блоке устройства хранения данных. Это эффективно для вычисления, но не для устройства хранения данных.

можно найти намного больше информации в веб-сайты Unicode и ICU.

C11 и <uchar.h>

стандарт C11 изменил правила, но не все реализации догнали изменения даже сейчас (середина 2017). Стандарт C11 суммирует изменения для поддержки Unicode как:

  • символы Unicode и строки (<uchar.h>) (первоначально указанный в ISO/IEC TR 19769:2004)

, Что следует, являются пустой минимальной схемой функциональности. Спецификация включает:

6.4.3 Универсальных имен персонажей

Синтаксис
универсальное имя персонажа:
        \u шестнадцатеричная четверка
        \U шестнадцатерично-квадратическая шестнадцатеричная четверка
шестнадцатеричная четверка:
        шестнадцатерично-разрядный шестнадцатерично-разрядный шестнадцатерично-разрядный шестнадцатерично-разрядный

7.28 утилит Unicode <uchar.h>

заголовок <uchar.h> объявляет типы и функции для управления символами Unicode.

объявленные типы mbstate_t (описаны в 7.29.1) и size_t (описанный в 7,19);

char16_t

, который является типом беззнаковых целых чисел, используемым для 16-разрядных символов, и является тем же типом как [1 112] (описанный в 7.20.1.2); и

char32_t

, который является типом беззнаковых целых чисел, используемым для 32-разрядных символов, и является тем же типом как [1 113] (также описанный в 7.20.1.2).

(Перевод перекрестных ссылок: <stddef.h> определяет size_t, <wchar.h> определяет mbstate_t, и <stdint.h> определяет uint_least16_t и uint_least32_t.) <uchar.h> заголовок также определяет минимальный набор (прерываемых) функций преобразования:

  • mbrtoc16()
  • c16rtomb()
  • mbrtoc32()
  • c32rtomb()

существуют правила, о которых символы Unicode могут использоваться в идентификаторах с помощью \unnnn или \U00nnnnnn нотации. Вам, вероятно, придется активно активировать поддержку таких символов в идентификаторах. Например, GCC требует -fextended-identifiers позволять их в идентификаторах.

Примечание, которое macOS Горная цепь (10.12.5), для именования, но одна платформа, не поддерживает <uchar.h>.

37
ответ дан Jonathan Leffler 9 February 2009 в 05:53
поделиться

Из того, что я знаю, wchar_t является зависящим от реализации (как видно из этого статья Wiki). И это не unicode.

1
ответ дан PolyThinker 9 February 2009 в 05:53
поделиться
  • 1
    Кроме того, эпоха UNIX о EOL в ближайшем будущем и ожидании будущего, не рекомендуется использовать strtotime(), если у Вас есть возможность использовать DateTime объект. + strtotime() не всегда соответствует, и это знало проблемы, но ответ будет определенно работать на большинство случаев. – Paul T. Rawkeen 28 July 2012 в 21:24

Самое важное - всегда четко различать текстовые и двоичные данные . Попробуйте следовать модели Python 3.x str против байтов или SQL ТЕКСТ против BLOB .

К сожалению, C сбивает с толку, используя char как для «символа ASCII», так и для int_least8_t . Вы захотите сделать что-то вроде:

typedef char UTF8; // for code units of UTF-8 strings
typedef unsigned char BYTE; // for binary data

Вам могут понадобиться typedef для кодовых единиц UTF-16 и UTF-32, но это более сложно, потому что кодировка wchar_t не определена. Вам понадобится только препроцессор #if s. Вот некоторые полезные макросы в C и C ++ 0x:

  • __ STDC_UTF_16 __ - Если определено, тип _Char16_t существует и является UTF-16.
  • __ STDC_UTF_32 __ - Если определено, тип _Char32_t существует и является UTF-32.
  • __ STDC_ISO_10646 __ - Если определено, то wchar_t будет UTF-32.
  • _WIN32 - В Windows wchar_t является UTF-16, хотя это нарушает стандарт.
  • WCHAR_MAX - Может использоваться для определения размера wchar_t , но не для определения того, использует ли ОС его для представления Unicode.

Означает ли это, что мой код должен нигде не используйте типы символов, и что необходимо использовать функции, которые могут иметь дело с wint_t и wchar_t?

См. также:

Нет.UTF-8 - это совершенно допустимая кодировка Unicode, в которой используются строки char * . Его преимущество заключается в том, что если ваша программа прозрачна для байтов, отличных от ASCII (например, конвертер окончания строки, который действует на \ r и \ n , но пропускает другие символы без изменений), вам вообще не нужно вносить никаких изменений!

Если вы используете UTF-8, вам нужно будет изменить все предположения, что char = символ (например, не вызывайте toupper в цикле) или char = столбец экрана (например, для переноса текста).

Если вы выберете UTF-32, у вас будет простота символов фиксированной ширины (но не графем фиксированной ширины , но вам нужно будет изменить тип всех ваших строк).

Если вы выберете UTF-16, вам придется отказаться как от предположения о символах фиксированной ширины , так и от предположения о 8-битных единицах кода, что делает этот путь обновления наиболее трудным. однобайтовые кодировки.

Я бы рекомендовал активно избегать wchar_t , потому что он не кроссплатформенный: иногда это UTF-32, иногда UTF-16, а иногда это восточноазиатская кодировка до Unicode. Я бы рекомендовал использовать typedef

Что еще более важно, избегайте TCHAR .

3
ответ дан 24 November 2019 в 10:01
поделиться
Другие вопросы по тегам:

Похожие вопросы: