Что "не так" С C++ wchar t и wstrings? Каковы некоторые альтернативы широким символам?


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

3 76

3 ответа:

что такое wchar_t?

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

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

- C++ [basic.основополагающим] 3.9.1/5

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

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

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

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

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

какая польза от wchar_t сегодня?

не так много, для портативного кода в любом случае. Если __STDC_ISO_10646__ определяется тогда значения wchar_t непосредственно представляют собой кодовые точки Юникода с одинаковыми значениями во всех локалях. Это делает его безопасным для выполнения преобразований между языками, упомянутых ранее. Однако вы не можете полагаться только на него, чтобы решить, что вы можете использовать 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 требуют его.

варианты

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

одна вещь, которую UTF-8 не предоставляет, - это возможность использовать простые текстовые алгоритмы, такие как ASCII. При этом UTF-8 ничем не хуже любой другой кодировки Юникода. На самом деле это может считаться лучше, потому что представления нескольких кодов в 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 префикс).

альтернативы, чтобы избежать

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


1. Символы, которые представимы в строках wchar_t, но которые не поддерживаются ни в одном языковом стандарте, не должны быть представлены одним значением wchar_t. Это означает, что wchar_t может использовать переменную ширину кодировка для определенных символов, еще одно явное нарушение намерения wchar_t. хотя можно утверждать, что символ, представляемый wchar_t, достаточно сказать, что локаль "поддерживает" этот символ, и в этом случае кодировки переменной ширины не являются законными, а использование окна UTF-16 не соответствует.

2. Unicode позволяет представлять множество символов с несколькими кодовыми точками, что создает те же проблемы для простых текстовых алгоритмов, что и кодировки переменной ширины. Даже если строго поддерживать составленную нормализацию, некоторые символы по-прежнему требуют нескольких кодовых точек. Смотрите:http://www.unicode.org/standard/where/

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

что, к сожалению, совсем не так. "Широкие символы" - это не обязательно 2 байта, на всех платформах, при любых обстоятельствах.

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

и я честно считаю, что лучший способ справиться с" 8-битными ASCII "против" Win32 wide characters "против" wchar_t-in-general "- это просто принять, что" Windows отличается"... и код соответственно.

ИМХО...

PS:

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

на Windows, у вас действительно нет выбора. Его внутренние API были предназначен для ПСК-2, что было разумно в то время, так как он был перед кодировками переменной длины UTF-8 и UTF-16 были стандартизированный. Но теперь, когда они поддерживают UTF-16, они закончили с худший из обоих миров.

обязательного чтения:

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 и позже, я считаю, по умолчанию 16-бит для C / C++ в любом случае (часть причины, по которой я все еще использую MSVS 6.0 всякий раз, когда могу ;)).

один другие хорошие (хотя и несколько устаревшие ссылки):