Not a kernel guy

… in the Windows kernel team

Sunday, June 3, 2007

А как насчёт скрестить UTF-8 и Win32 API?

Пришла давеча в голову совсем неоригинальная мысль – а почему ещё никто не сделал надстройку над Win32 API, позволяющую использовать строки, закодированные в UTF-8? Ведь существует же масса причин, чтобы такая библиотека пользовалась бы спросом, особенно несколько лет назад – во время массовой миграции с 9x на NT.

  1. Такую библиотеку несложно написать. Базовая инфраструктура в виде ANSI и Unicode вариантов одних и тех же Win32 функций существует. C и C++ поддерживают многобайтные символы (MBCS), в том числе и UTF-8.
  2. Перекодирование из UTF-8 в UTF-16 и обратно может показаться затратным, однако, к примеру, Wow64 делает фактически то же самое, перекодируя 32-х битные параметры в 64-х битные при каждом системном вызове и никакой особенной деградации производительности не заметно.
  3. Опыт применения UTF-8 в Unix мире показывает, что большинство ANSI приложений может без особых проблем работать с UTF-8 строками. Конечно, есть и отличия, но они легко обходятся.
  4. Переделка большого ANSI приложения в Unicode вариант, работающий с двухбайтовыми строками, весьма сложная и затратная процедура, требующая времени и немалого опыта от разработчиков. Перевод приложения на UTF-8. по всей видимости, должен быть значительно проще.

Конечно же, есть случаи, когда переход на UTF-8 сам по себе ничего не даёт, однако в большинстве ситуаций это вполне оправдано. Так почему же никто таким не пользуется?

PS: Беглый поиск в Интернете дал ссылку только одну ссылку UTF-8 Cygwin. Однако не удалось найти ни одной реализации для чистого Windows окружения.

Posted at 4:38 pm •

RSS feed | Trackback URI

9 Comments »

Trackback by Зеркало: Not a kernel guy — June 3, 2007 @ 5:20 pm

А как насчёт скрестить UTF-8 и Win32 API?…

Пришла давеча в голову совсем неоригинальная мысль – а почему ещё никто не сдела…

 
Comment by Александр — June 4, 2007 @ 3:23 am

А я уже сделал.
Очень просто - создал клон класса CString (очень старый, от VC++ 4.0), выкинув из него двухбайтовость и левую многобайтность. Все хранение в однобайтном буфере (т.е. char *) строки UTF-8. Разумеется, конструкторы из CString и переопределенное присваивание.

Я не стал переделывать системные вызовы. Везде, где надо, я в мои классы добавляю временную переменную типа CString, а в вызове делаю SomeStr.ToStr(cstr).
Разумеется, это не так удобно, как обертывание всего API, но работает зашибись.
К примеру, я смог использовать xgettext для интернационализации своих программ, что на порядок круче отстоя с интернационализацией ресурсов.
Теперь языки у меня переключаются динамически прямо в запущенной программе, из меню.

Производительность не пострадала - т.е. я не заметил тормозов. Хотя специально не замерял.

 
Comment by кирилл — June 4, 2007 @ 5:25 am

Некоторые из стандартных Windows функций имеют UTF-8 overload-ы. Например - DNS функции. Загляните в список экспорта из DNSAPI.DLL и сможете увидеть например такое:
DnsValidateName_A
DnsValidateName_UTF8
DnsValidateName_W

 
Comment by Not a kernel guy — June 4, 2007 @ 11:33 am

 

Некоторые из стандартных Windows функций имеют UTF-8 overload-ы.

Интересно, не знал об этом.

 
Comment by Eugene Golushkov — June 5, 2007 @ 6:46 am

О поддержке UTF-8 в реальных проектах, которые рождались как ANSI великолепно написал Michael Caplan здесь http://blogs.msdn.com/michkap/archive/2007/05/11/2547703.aspx
Он описывает нюансы, приведшие к прекращению поддержки UTF-8 в VCRT 8.0, и, насколько я понимаю, все доводы применимы и к MSLU.

Цитата: But to be honest, given that every project I have ever seen that claimed to support UTF-8 failed in the 3/4 byte cases (some even failed in the 2-byte cases!)

А еще нужно учесть, что длина UTF-8 представления символа из UCS-4 может быть до 6 байт (для code points за пределами первых 17 плоскостей, rfc2279).

 
Comment by Not a kernel guy — June 5, 2007 @ 9:37 pm

Не могу сказать что аргументы Майкла звучат убедительно. По моему, всё что он сказал это то, что проекты использующие UTF-16 поддерживают Unicode лучше чем UTF-8 аналоги только потому, что и там и там разработчики лажают с поддержкой многосимвольных последовательностей. Просто в один символ UTF-16 можно запихать гораздо больше разных кодировок, чем в в один символ UTF-8.

 
Comment by Eugene Golushkov — June 6, 2007 @ 1:48 pm

Сколько разных программистов, зная что в тексте ровно N байт выделяют для смены кодировки буфер размером 2*N , в неявном предположении, что при конвертации объем не может увеличиться больше чем в два раза? При этом число 2 скорее всего замаскировано чем-то вроде sizeof(wchar_t), если программист знает, что на Unix-ах wchar_t четырехбайтный. И большинство кодировок (все single-byte) вполне отвечают этому эмпирическому правилу, что позволяет таким ошибкам жить в коде, которому уже довольно много лет.

Так что мы имеем два отрицательных момента. Первый состоит в том, что программисту нужно быть много аккуратнее в управлении памятью при добавлении поддержки UTF-8, так как максимальный размер символа может достигать 6-ти байт для UCS-4, 4-х байт для UTF-16 и 3-х байт для Basic Multilingual Plane. В сравнении с этим правила UTF-16 просты до безобразия - 2 байта для Basic Multilingual Plane и 4 байта для азиатских языков.

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

Ну и в качестве курьеза, который показывает, что за аргументацией Майкла Каплана возможно стоит нечто большее, чем абстрактные рассуждения. Google для запроса “utf-16 problem” находит 380 000 ссылок, а для “utf-8 problem” - 5 900 000. Разница более чем в 15 раз :)

 
Comment by Not a kernel guy — June 6, 2007 @ 10:04 pm

Да я согласная, согласная я. :-) За исключением ремарки про UCS-4. UTF-16 тоже не способна закодировать всё многообразие UCS-4.

Моя мысль состоит в том, что при переделки ANSI проекта в Unicode в случае UTF-16 делается двойная работа - сначала все переводится на UCS-2, а потом, когда обнаруживается, что UCS-2 и UTF-16 это не одно и тоже, начинаются заделываться дырки с surrogate characters. И это если не затрагивать символов вроде ударений и прочих, имеющих культурно/лингвистическое значение.

В случае же с UTF-8 массу усилий, которые в “нормальном” случае тратяться на героическую замену strlen на wstrlen (а по уму - сразу на StringCchLength), можно потратить на искоренение “лингвистисеких” проблем.

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

 
Pingback by Not a kernel guy : Blog Archive : Win32.Utf8. — August 12, 2007 @ 10:40 pm

[...] тут совсем недавно удивлялся почему нет библиотек, эмулирующих поддержку UTF-8 на [...]

 

Your Comment (smaller | larger)

You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Powered by WordPress