Я видел, как много людей в сообществе C ++ (особенно ## c ++ на freenode) возражали против использования wstrings
и wchar_t
и их использования в API Windows. Что на самом деле «не так» с wchar_t
и wstring
, и если я хочу поддержать интернационализацию, каковы альтернативы широким символам?
86
Ответы:
Что такое wchar_t?
wchar_t определен таким образом, что любая кодировка символов языкового стандарта может быть преобразована в представление wchar_t, где каждый wchar_t представляет ровно одну кодовую точку:
Это не требует, чтобы wchar_t был достаточно большим для одновременного представления любого символа из всех языков. То есть кодировка, используемая для wchar_t, может отличаться в зависимости от локали. Это означает, что вы не можете обязательно преобразовать строку в wchar_t, используя один языковой стандарт, а затем преобразовать обратно в char, используя другой языковой стандарт. 1
Поскольку использование wchar_t в качестве общего представления для всех локалей, по-видимому, является основным применением wchar_t на практике, вы можете задаться вопросом, для чего он нужен, если не для этого.
Первоначальное намерение и цель wchar_t состояли в том, чтобы упростить обработку текста, определив его таким образом, чтобы он требовал однозначного сопоставления кодовых единиц строки с символами текста, что позволяло использовать те же простые алгоритмы, которые используются со строками ascii для работы с другими языками.
К сожалению, формулировка спецификации wchar_t предполагает взаимно-однозначное сопоставление между символами и кодовыми точками для достижения этого. Unicode нарушает это предположение 2 , поэтому вы также не можете безопасно использовать wchar_t для простых текстовых алгоритмов.
Это означает, что переносимое программное обеспечение не может использовать wchar_t ни в качестве общего представления текста между языками, ни для включения использования простых текстовых алгоритмов.
Какая польза от wchar_t сегодня?
Во всяком случае, для переносимого кода немного. Если
__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.
Альтернативы
Альтернатива, которая мне нравится, - использовать строки 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
префикс) .Альтернативы, которых следует избегать
TCHAR: TCHAR предназначен для переноса старых программ Windows, которые предполагают устаревшие кодировки с char на wchar_t, и о нем лучше забыть, если ваша программа не была написана в каком-то предыдущем тысячелетии. Он не переносится и по своей сути не специфичен в отношении своей кодировки и даже типа данных, что делает его непригодным для использования с любым API, не основанным на TCHAR. Поскольку его целью является переход на wchar_t, что, как мы видели выше, не очень хорошая идея, в использовании TCHAR нет никакой пользы.
1. Символы, которые могут быть представлены в строках wchar_t, но которые не поддерживаются ни в одной локали, не обязательно должны быть представлены одним значением wchar_t. Это означает, что wchar_t может использовать кодировку переменной ширины для определенных символов, что является еще одним явным нарушением намерения wchar_t. Хотя можно утверждать, что символа, представленного с помощью wchar_t, достаточно, чтобы сказать, что локаль «поддерживает» этот символ, и в этом случае кодировки переменной ширины недопустимы, а использование Window UTF-16 не соответствует требованиям.
2. Unicode позволяет представлять множество символов с помощью нескольких кодовых точек, что создает те же проблемы для простых текстовых алгоритмов, что и кодирование переменной ширины. Даже если строго соблюдается составная нормализация, некоторые символы все равно требуют нескольких кодовых точек. См .: http://www.unicode.org/standard/where/
источник
fopen
файл, имя которого содержит символы, отличные от ANSI.В wchar_t нет ничего «плохого». Проблема в том, что еще во времена NT 3.x Microsoft решила, что Unicode - это хорошо (это так), и реализовала Unicode в виде 16-битных символов wchar_t. Таким образом, большая часть литературы Microsoft середины 90-х в значительной степени приравнивается к Unicode == utf16 == wchar_t.
К сожалению, это совсем не так. «Широкие символы» не обязательно состоят из 2 байтов на всех платформах и при любых обстоятельствах.
Это один из лучших праймеров по Unicode (независимо от этого вопроса, независимо от C ++), который я когда-либо видел: я очень рекомендую его:
И я искренне верю, что лучший способ справиться с «8-битным ASCII», «широкими символами Win32» и «wchar_t-in-general» - это просто признать, что «Windows отличается» ... и код соответственно.
ПО МОЕМУ МНЕНИЮ...
PS:
Я полностью согласен с приведенным выше jamesdlin:
источник