Вопрос по internationalization, wstring, winapi, c++, unicode – Что «не так» с C ++ wchar_t и wstrings? Какие есть альтернативы широким символам?

79

Я видел много людей в сообществе C ++ (особенно ## c ++ на freenode), возмущенных использованиемwstrings а такжеwchar_tИ их использование в Windows API. Что именно "не так"? сwchar_t а такжеwstringи если я хочу поддержать интернационализацию, какие есть альтернативы широким символам?

Есть какие-либо ссылки на это? Dani
В Windows у вас действительно нет выбора. Его внутренние API были разработаны для UCS-2, что было разумно в то время, так как это было до стандартизации кодировок UTF-8 и UTF-16 переменной длины. Но теперь, когда они поддерживают UTF-16, они оказались в худшем из обоих миров. jamesdlin
utf8everywhere.org имеет хорошее обсуждение причин, чтобы избежать широких символов. Joe Gauterin
@jamesdlin Конечно, у вас есть выбор. Библиотека nowide предоставляет удобный способ преобразования строк только при переходе к API. Вызовы API со строками обычно низкочастотны, поэтому разумным способом является преобразование ad-hok и постоянное наличие файлов и внутренних переменных в UTF-8. Pavel Radzivilovsky
Возможно, эта удивительная тема ответит на все ваши вопросы?stackoverflow.com/questions/402283/stdwstring-vs-stdstring MrFox

Ваш Ответ

3   ответа
17

что еще в NT 3.x дни Microsoft решила, что Unicode был хорошим (он есть), и реализовала Unicode как 16-битные символы wchar_t. Таким образом, большая часть литературы Microsoft середины 90-х годов в значительной степени приравнивается к Юникоду == utf16 == wchar_t.

К сожалению, это совсем не так. & quot; Широкие символы & quot; являютсяnot обязательно 2 байта, на всех платформах, при любых обстоятельствах.

Это один из лучших учебников по «Юникоду» (независимо от этого вопроса, независимо от C ++), который я когда-либо видел: Ihighly рекомендовать его:

http://www.joelonsoftware.com/articles/Unicode.html

И я искренне верю, что лучший способ справиться с «8-битным ASCII» против & quot; широких символов Win32 & quot; vs & quot; wchar_t-in-general & quot; это просто принять, что «Windows отличается» ... и код соответственно.

ПО МОЕМУ МНЕНИЮ...

PS:

Я полностью согласен с Jamesdlin выше:

On Windows, you don't really have a choice. Its internal APIs were designed for UCS-2, which was reasonable at the time since it was before the variable-length UTF-8 and UTF-16 encodings were standardized. But now that they support UTF-16, they've ended up with the worst of both worlds.

-3

The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)

Если вы программируете на Java или .Net (VB.Net или C #) - это, по большей части, не проблема: оба по умолчанию являются Unicode. Если вы программируете на «классический» Win32 API), лучше всего использовать макросы TCHAR и _T () (а не явно использовать wchar).

Я полагаю, что все компиляторы Microsoft VS2005 и более поздние версии по умолчанию для C / C ++ по умолчанию 16-битные (отчасти я все еще использую MSVS 6.0, когда могу;)).

Еще одно хорошее (хотя и несколько устаревшее, чернила):

http://www.codeproject.com/Articles/2995/The-Complete-Guide-to-C-Strings-Part-I-Win32-Chara
paulsm4: Юникод имеетmany different encodingsЭто не так просто, как вы хотите. На самом деле, UTF-8 обратно совместим с ASCII (в отличие от других кодировок), так что этот трудный выбор "ASCII" или "Юникод" это не проблема.
@ Inverse & quot;UTF-8 is backwards compatible with ascii& Quot; или нет, в зависимости от того, как вы определяете «обратную совместимость».
& quot; использовать Unicode & quot; хотя этого недостаточно. Вы должны выбирать между кодировками Unicode, вы должны выбирать типы данных и т. Д.
Я не думаю, что это не проблема в Java / .NET просто потому, что оба по умолчанию являются "Unicode". Это связано с тем, что языки задают кодировку, поэтому каждый использует ее последовательно. Также я не согласен с тем, что использование TCHAR является хорошей идеей в современных программах. TCHAR предназначен для переноса древних программ с char на wchar_t.
Простой ответ - «использовать ASCII». или & quot; использовать Unicode & quot ;. Все остальное - "шум". И, нравится вам это или нет, "wchar_t" в основном == Юникод в Win32 C ++. Для Windows (и только Windows) я бы рекомендовал использовать TCHAR вместо необработанного wchar_t для общего текста. Я также рекомендую использовать std :: string вместо массивов char / wchar. И, честно говоря, я бы рекомендовал использовать Java, C #, C или простоanything над C ++. ПО МОЕМУ МНЕНИЮ...
112
What is wchar_t?

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

Type wchar_t is a distinct type whose values can represent distinct codes for all members of the largest extended character set specified among the supported locales (22.3.1).

                                                                               — C++ [basic.fundamental] 3.9.1/5

этоdoes not требует, чтобы wchar_t был достаточно большим, чтобы представлять любой символ из всех локалей одновременно. То есть кодировка, используемая для wchar_t, может отличаться в разных локалях. Это означает, что вы не можете обязательно преобразовать строку в wchar_t, используя одну локаль, а затем преобразовать обратно в char, используя другую локаль.1

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

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

К сожалению, формулировка спецификации wchar_t предполагает взаимно-однозначное сопоставление символов и кодовых точек для достижения этой цели. Юникод нарушает это предположение2Таким образом, вы также не можете безопасно использовать wchar_t для простых текстовых алгоритмов.

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

What use is wchar_t today?

Не так много, для переносимого кода в любом случае. Если__STDC_ISO_10646__ определяется, тогда значения wchar_t напрямую представляют кодовые точки Unicode с одинаковыми значениями во всех локалях. Это делает безопасным выполнение преобразований между локалями, упомянутых ранее. Однако вы не можете полагаться только на него, чтобы решить, что вы можете использовать wchar_t таким образом, потому что, хотя большинство платформ Unix определяют его, Windows не делает этого, хотя Windows использует одну и ту же локаль wchar_t во всех локалях.

Причина, по которой Windows не определяет__STDC_ISO_10646__ это связано с тем, что Windows использует UTF-16 в качестве своей кодировки wchar_t, и потому что UTF-16 использует суррогатные пары для представления кодовых точек, больших чем U + FFFF, что означает, что UTF-16 не удовлетворяет требованиям для__STDC_ISO_10646__.

Для платформы, специфичной для кода, wchar_t может быть более полезным. Это по существу требуется в Windows (например, некоторые файлы просто не могут быть открыты без использования имен файлов wchar_t), хотя, насколько я знаю, Windows является единственной платформой, где это верно (поэтому, возможно, мы можем думать о wchar_t как о «Windows_char_t»); ).

Оглядываясь назад, wchar_t явно не полезен для упрощения обработки текста или в качестве хранилища для независимого от локали текста. Переносимый код не должен пытаться использовать его для этих целей. Непереносимый код может оказаться полезным просто потому, что это требуется некоторым API.

Alternatives

Мне нравится альтернатива - использовать C-строки в кодировке UTF-8, даже на платформах, не особенно дружественных к UTF-8.

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

UTF-8 не предоставляет возможности использовать простые текстовые алгоритмы, которые возможны в ASCII. При этом UTF-8 ничем не хуже любой другой кодировки Unicode. Фактически, это может считаться лучшим, потому что многокодовые представления единиц в UTF-8 более распространены, и поэтому ошибки в обработке кода, такие представления символов переменной ширины, с большей вероятностью будут замечены и исправлены, чем если вы попытаетесь придерживаться UTF -32 с NFC или NFKC.

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

Другой альтернативой, используемой некоторыми программами, является выбор кроссплатформенного представления, например, коротких массивов без знака, содержащих данные в формате UTF-16, а затем обеспечение всей поддержки библиотеки и просто затраты на поддержку языка и т. Д.

C ++ 11 добавляет новые виды широких символов в качестве альтернатив wchar_t, char16_t и char32_t с сопутствующими функциями языка / библиотеки. На самом деле это не гарантированно UTF-16 и UTF-32, но я не думаю, что в какой-либо крупной реализации будет использоваться что-то еще. C ++ 11 также улучшает поддержку UTF-8, например, с помощью строковых литералов UTF-8, поэтому нет необходимости обманывать VC ++ для создания строк в кодировке UTF-8 (хотя я могу продолжать делать это, а не использоватьu8 префикс).

Alternatives to avoid

TCHAR: TCHAR предназначен для переноса древних программ Windows, которые принимают устаревшие кодировки, из char в wchar_t, и о нем лучше всего забыть, если ваша программа не была написана в каком-то предыдущем тысячелетии. Он не является переносимым и по своей природе не специфичен в отношении своего кодирования и даже типа данных, что делает его непригодным для использования с любым API, не основанным на TCHAR. Поскольку его целью является переход на wchar_t, что, как мы видели выше, не является хорошей идеей, нет никакого смысла в использовании TCHAR.

1. Characters which are representable in wchar_t strings but which are not supported in any locale are not required to be represented with a single wchar_t value. This means that wchar_t could use a variable width encoding for certain characters, another clear violation of the intent of wchar_t. Although it's arguable that a character being representable by wchar_t is enough to say that the locale 'supports' that character, in which case variable-width encodings aren't legal and Window's use of UTF-16 is non-conformant.

2. Unicode allows many characters to be represented with multiple code points, which creates the same problems for simple text algorithms as variable width encodings. Even if one strictly maintains a composed normalization, some characters still require multiple code points. See: http://www.unicode.org/standard/where/

Дополнение:utf8everywhere.org рекомендует использовать UTF-8 в Windows, а Boost.Nowide запланирован для официальной проверки.
@ dan04 Да, вы не можете использовать стандартную библиотеку в Windows, но вы можете создать переносной интерфейс, который оборачивает стандартную библиотеку на других платформах и конвертирует из UTF-8 в wchar_t непосредственно перед использованием функций Win32 W.
@ paulsm4: удачи в портировании вашего кода.
@BrendanMcK. Конечно, код, который использует Win32 API в Windows и другие API в других системах, не существует. Правильно? Проблема с подходом Microsoft («использовать wchar внутри вашего приложения») заключается в том, что он затрагивает даже код, который не взаимодействует с системой напрямую иcould быть портативным
Проблема в том, что выhave использовать специфичные для Windows функции, поскольку решение Microsoft не поддерживать UTF-8 в качестве кодовой страницы ANSI «ломается»; Стандартная библиотека C (++). Например, вы не можетеfopen файл, имя которого содержит символы, отличные от ANSI.

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