Что такое wchar t

Программирование с использованием широких символов wchar_t

Стандарт ISO C90 ввел тип широких символов wchar_t, тем самым назначив официальный стандарт для широких символов в языке Си. Однако его использование не очень хорошо понимается программистами на Си, и отладка широких символов с помощью отладчика GDB является проблемой, решить которую могут немногие. В результате многие программисты прибегают к использованию массивов символов ASCII, что не очень хорошо; Сегодня локализованный код имеет все большее значение.

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

По факту для широких символов лучше использовать тип int32_t определенный в заголовке stdint.h т.к. было сказано выше не во всех системах wchar_t это четыре байта, а int32_t во всех. Функции для работы с широкими символами прекрасно работают с типом int32_t

Нюансы при работе с функциями

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

Использование широких символов требует, чтобы вы были более осторожны с этими единицами. Например, один символ может занимать более одного столбца экранного пространства, но модификаторы длины в строке формата printf принимают свой размер в байтах. Решений несколько. Одно из них использование функций wcslen и wcswidth:

Используйте функции wcslen при выделении памяти для широких символов и используйте wcswidth для выравнивания текста при печати.

Вторым решением является использование функций специально предназначенных для работы с широкими символами о них далее.

Печать

Спецификатор преобразования строки формата printf для массивов широких символов выглядит так %ls. Вы не должны использовать %s т.к. это определено только в Единой спецификации UNIX версии 2, но не в стандарте ISO C.

При использовании wprintf или fwprintf выходной поток должен быть в режиме широких символов. Чтобы переключить выходной поток, используйте fwide. Например, чтобы переключить стандартный вывод в режим широких символов:

Применение строковых функций

Широкие символы и многобайтовые строки

Широкие символы это конечно классно, но не экономно. Широкие символы это всегда фиксированный размер, даже если фактически символ умещается в один байт. Для пущей экономии придумали кодировки с переменным кол-вом байтов аля UTF-8 которые используют память более экономно, за счет более хитрого кодирования (там в первом октете символа кодируется длина этого самого символа в октетах, а последующих октетах в общем то идет полезная нагрузка) тут наглядно объяснено: How About UNICODE and UTF-8 Так вот такие кодировки с переменным количеством байт на символ кодируются Многобайтовыми строками.

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

Отображение широких символов ASCII в GDB

Хотя эти две проблемы, безусловно, являются насущними, разработчикам не удалось добавить в GDB базовую поддержку для печати простых символов ASCII, что требует исправления.

Я написал скрипт, чтобы сделать это возможным, определив новую команду wchar_print (ее должно хватить для ввода wc ). Вы можете скачать его и использовать его несколькими способами:

Вы можете вызвать функцию с указателем на wchar_t:

Обратите внимание, что wchar_print будет давать неправильные результаты для широких символов со значением больше 127.

Источник

char, wchar_t, char8_t, char16_t, char32_t

Синтаксис

Remarks

wchar_t Тип является определяемым реализацией типом расширенных символов. в компиляторе майкрософт он представляет 16-разрядный символ, используемый для хранения юникода в кодировке UTF-16le, собственный тип символов в операционных системах Windows. версии расширенных символов функций библиотеки универсальной среды выполнения C (UCRT) используют wchar_t и его указатели и типы массивов в качестве параметров и возвращаемых значений, как и версии расширенных символов собственного API Windows.

char8_t Типы, char16_t и char32_t представляют 8-разрядные, 16-разрядные и 32-разрядные символы, соответственно. ( char8_t является новым в c++ 20 и требует /std:c++20 /std:c++latest параметр компилятора или.) Юникод в кодировке UTF-8 может храниться в char8_t типе. Строки char8_t и char типа называются char8_t строками, даже если они используются для кодирования Юникода или многобайтовых символов. Юникод в кодировке UTF-16 может храниться в char16_t типе, а Юникод в кодировке UTF-32 может храниться в char32_t типе. Строки этих типов и wchar_t все они называются wchar_t строками, хотя термин часто относится к строкам wchar_t типа.

В стандартной библиотеке C++ basic_string тип является специализированным для узких и широких строк. Используйте, если символы имеют тип, если символы имеют тип, если символы имеют тип, std::string char а также std::u8string char8_t std::u16string char16_t std::u32string char32_t std::wstring когда символы wchar_t имеют тип. Другие типы, представляющие текст, включая std::stringstream и, std::cout имеют специализации для узких и расширенных строк.

Источник

Что такое TCHAR, WCHAR, LPSTR, LPWSTR,LPCTSTR (итд)

Что такое wchar t. Смотреть фото Что такое wchar t. Смотреть картинку Что такое wchar t. Картинка про Что такое wchar t. Фото Что такое wchar t

Многие C++ программисты, пишущие под Windows часто путаются над этими странными идентификаторами как TCHAR, LPCTSTR. В этой статье я попытаюсь наилучшим способом расставить все точки над И. И рассеять туман сомнений.

В свое время я потратил много времени копаясь в исходниках и не понимал что значат эти загадочные TCHAR, WCHAR, LPSTR, LPWSTR,LPCTSTR.
Недавно нашел очень грамотную статью и представляю ее качественный перевод.
Статья рекомендуется тем кто бессонными ночами копошиться в кодах С++.

В общем, символ строки может быть представлен в виде 1-го байта и 2-х байтов.
Обычно одно-байтовый символ это символ кодировки ANSI- в этой кодировке представлены все английские символы. А 2-х байтовый символ это кодировка UNICODE, в которой могут быть представлены все остальные языки в мире.

Компилятор Visual C++ поддерживает char и wchar_t как встроенные типы данных для кодировок ANSI и UNICODE.Хотя есть более конкретное определение Юникода, но для понимания, ОС Windows использует именно 2-х байтовую кодировку для много языковой поддержки приложений.

Для представления 2-х байтовой кодировки Юникод Microsoft Windows использует UTF16-кодирование.
Microsoft стала одна из первых компаний которая начала внедрять поддержку Юникода в своих операционных системах (семейство Windows NT).

Что делать если вы хотите чтобы ваш С/С++ код был независимым от кодировок и использование разных режимов кодирования?

СОВЕТ. Используйте общие типы данных и имена для представления символов и строк.

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

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

В настройках проекта на вкладке GENERAL есть параметр CHARACTER SET который указывает в какой кодировке будет компилироваться программа:

Что такое wchar t. Смотреть фото Что такое wchar t. Смотреть картинку Что такое wchar t. Картинка про Что такое wchar t. Фото Что такое wchar t

Если указан параметр «Use Unicode Character set», тип TCHAR будет транслироваться в тип wchar_t. Если указан параметр «Use Multi-byte character set» то тогда TCHAR будет транслироваться в тип char. Вы можете свободно использовать типы char и wchar_t, и настройки проекта никоим образом не повлияют на использование этих ключевых слов.

TCHAR определен так:

Макрос _UNICODE будет включен если вы укажите «Use Unicode Character set» и тогда тип TCHAR будет определен как wchar_t. Когда же вы укажите «Use Multi-byte character set» TCHAR будет определен как char.

Помимо этого, для того что была поддержка нескольких наборов символов используя общий базовый код, и возможно поддержки много языковых приложений, используйте Специфические функции (то есть макросы).
Вместо того чтобы использовать strcpy, strlen, strcat (в том числе защищенные варианты функции с префиксом _s), или wcscpy, wcslen, wcscat (включая защищенные варианты), вам лучше использовать функции _tcscpy, _tcslen, _tcscat.

Как вы знаете функция strlen описана так:

И функция wcslen описана так:

Вам лучше использовать _tcslen, который логически описан так:

WC это Wide Character (Большой символ). Поэтому, wcs функции будут для wide-character-string (то есть для большой-символьной-строки).Таким образом _tcs будет означать _T символьная строка. И как вы знаете строки с префиксом _T могут быть типа char или wchar_t.

Но в реальности _tcslen (и другие функции с префиксом _tcs) вовсе не функции, это макросы. Они просто описаны как:

Вы можете просмотреть заголовочный файл TCHAR.H и поискать там еще Макро описания похожее на вышеупомянутое.

Таким образом TCHAR оказывается вовсе не типом, а надстройкой над типами char и wchar_t. Позволяя тем самым выбирать мульти язычное приложение у нас будет или же все таки, одно язычное.

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

Для этого мы сделаем две различные функции:

И простой макрос скроет разницу между ними:

Клиент просто вызовет функцию как

Заметьте, что TCHAR и _TPrintChar теперь будут сопоставимы с UNICODE или ANSI, а переменная cChar и параметр функции будет сопоставим с типом данных char или wchar_t.

Макросы дают нам обойти эти сложности, и позволяют нам использовать ANSI или UNICODE функции для наших символов и строк. Множество функций Windows описаны именно таким образом, и для программиста есть только одна функция (то есть макрос) и это хорошо.

Приведу пример с SetWindowText:

Есть только несколько функций у которых нету таких макросов, и они только с суффиксом W или A. Пример тому функция ReadDirectoryChangesW, которая не имеет эквивалента в кодировки ANSI.

Как вы знаете, мы используем двойные кавычки для представления строк. Строка представленная в этой манере это ANSI-строка, на каждый символ используется 1 байт. Приведу пример:

Указанная верху строка не является строкой UNICODE, и не подходит для много языковой поддержки. Для того чтобы получить UNICODE строку вам надо использовать префикс L.
Приведу пример:

Поставьте спереди L и вы получите UNICODE строку. Все символы (Я повторяю все символы ) занимают 2 байта, включая Английские буквы, пробелы, цифры и символ null. Объем данных строки Unicode всегда будет кратен 2-м байтам. Строка Unicode длиной 7 символов будет занимать 14 байтов. Если строка Unicode занимает 15 байтов то это не правильная строка, и она не будет работать в любом контексте.

Также, строка будет кратна размеру sizeof(TCHAR) в байтах.

Когда Вам нужно жестко прописанный код, вы можете писать код так:

Строки без префикса это ANSI строки, с префиксом L строки Unicode, и строки с префиксом _T и TEXT зависимые от компиляции. И опять же _T и TEXT это снова макросы. Они определены так:

Символ ## это ключ(token) вставки оператора, который превратит _T(«Unicode») в L«Unicode», где строка это аргумент для макроса- если конечно _UNICODE определен.
Если _UNICODE не определен то _T(«Unicode») превратит это в «Unicode». Ключ вставки оператора существовал даже в языке С, и это не специфическая вещь связанная с кодировкой строк в VC++.

К сведению, макросы могут применятся не только для строк но и для символов. Например _T(‘R’) превратит это в L’R’ ну или в просто ‘R’. Тоесть либо в Unicode символ либо в ANSI символ.

Нет и еще раз нет, вы не можете использовать макрос чтобы конвертировать символ или строку в Unicode и не Unicode текст.
Следующий код будет неправильным:

Строки _T( c); _T(str); отлично скомпилируются в режиме ANSI, _T(x) превратится в x, и _T( c) вместе с _T(str) превратятся просто в c и str.
Но когда вы будете собирать проект в режиме Unicode код не с компилируется:

Я не хотел бы вызывать инсульт вашего интеллекта и объяснять почему это не работает.

Существует несколько функций для конвертирования Мульбайтовых строк в UNICODE, о которых я скоро расскажу.

Есть важное замечание, почти все функции которые принимает строку или символ, приоритетно в Windows API, имеют обобщенное название в MSDN и в других местах.
Функция SetWindowTextA/W будет классифицирована как:

Но как Вы знаете, SetWindowText это просто макрос, и в зависимости от настроек проекта будет рассматриваться как:

Так что не ломайте голову если не сможете получить адрес этой функции:

В библиотеке User32.DLL, имеются 2 функции SetWindowTextA и SetWindowTextW которые экспортируются, то есть тут нет имен с обобщенным названием.

Все функции которые имеют ANSI и UNICODE версию, вообще то имеют только UNICODE реализацию. Это значит, что когда Вы вызываете SetWindowTextA из своего кода, передавая параметр ANSI строку — она конвертирует ANSI в UNICODE вызывает SetWindowTextW.
Реальную работу (установку заголовка/названия/метки окна) делает только Unicode версия!

Возьмем другой пример, который будет получать текст окна, используя GetWindowText.
Вы вызываете GetWindowTextA передавая ему ANSI буфер как целевой буфер.
GetWindowTextA сначала вызовет GetWindowTextW, возможно выделяя память для Unicode строки (т.е массив wchar_t).
Затем он с конвертирует Unicode в ANSI строку для вас.

Поэтому очень рекомендуется вызывать напрямую Unicode функции.
В свою очередь, это означает, что вы всегда должны быть нацелены на сборку Unicode версии, а не на сборку ANSI версии, учитывая тот факт, что вы привыкли использовать ANSI строки в течение многих лет.

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

Замечание: Есть еще одно описание типа: имя ему WCHAR – оно эквивалентно wchar_t.

TCHAR это макрос, для декларирования одного символа. Вы также можете декларировать массив TCHAR. А что если Вы например захотите описать указатель на символы или, константный указатель на символы.
Приведу пример:

После чтения фишек с TCHAR, вы наверное предпочтете использовать именно его. Существуют еще хорошие альтернативы для представления строк в вашем коде. Для этого надо просто включить Windows.h в проект.
Примечание: Если ваш проект включает windows.h (косвенным или прямым образом), вы не должны включать в проект TCHAR.H.
Для начала пересмотрим старую функцию, чтобы было легче понять. Пример функцию strlen.

Которая может быть представлена по другому.

Где LPCSTR описан как:

LPCSTR понимается так.
• LP — Long Pointer (длинный указатель)
• C – Constant (константа)
• STR – String (строка)
По сути LPCSTR это (Длинный) указатель на строку.

Давайте изменим strcpy в соответствие с новым стилем имени типов:

szTarget имеет тип LPSTR, без использования типов языка С. LPSTR определен так:

Заметьте что szSource имеет тип LPCSTR, так как функция strcpy не модифицирует исходный буфер, поэтому выставлен атрибут const. Возвращаемый тип данных не константная строка: LPSTR.

Итак, функции с префиксом str для манипуляции с ANSI строками. Но нам нужна еще для двух байтовых Unicode строк. Для тех же больших символов имеются эквивалентные функции.
Для примера, чтобы посчитать длину символов больших символов(Unicode строки), вы будете использовать wcslen:

Прототип функции wcslen такой:

И код выше может быть представлен по другому:

Где LPCWSTR описан так:

LPCWSTR можно понять так:
LP — Long Pointer (Длинный указатель)
C — Constant (константа)
WSTR — Wide character String (строка больших символов)

Аналогичным образом, strcpy эквивалент wcscpy, для Unicode строк:

Который может быть представлен как:

Где szTarget это не константная большая строка (LPWSTR), а szSource константная большая строка.

Существует ряд эквивалентных wcs-функций для str-функций. str-функции будут использоваться для простых ANSI строк, а wcs-функции для Unicode строк.

Хотя Я уже советовал что надо использовать native Unicode функции, а не только ANSI или только синтезированные TCHAR функции. Причина проста — ваше приложение должно быть только Unicode-ным, и вы не должны заботится о том что спортируются ли они для ANSI. Но для полноты картины я и упомянул эти общие отображения (проецирования).

Чтобы вычислить длину строки, вы можете использовать _tcslen функцию (макро).
Который описан так:

Где имя типа LPCTSTR можно понять так
LP — Long Pointer (Длинный указатель)
C — Constant (Константа)
T = TCHAR
STR = String (Строка)

В зависимости от настроек проекта, LPCTSTR будет проецироваться в LPCSTR (ANSI) или в LPCWSTR (Unicode).

Заметьте: функции strlen, wcslen или _tcslen будут возвращать количество символов в строке, а не количество байтов.

Обобщенная операция копирования строки _tcscpy описана так:

Или в еще более обобщенной манере, как:

Вы можете догадаться что значит LPTSTR ))

Примеры использования.

Во первых приведу пример нерабочего кода:

На ANSI сборке, этот код успешно с компилируется потому что TCHAR будет типом char, и переменная name будет массивом char. Вызов strlen для name тоже будет прекрасно работать.

Итак. Давайте с компилируем тоже самое с включенными UNICODE/_UNICODE (в настройках проекта выберите «Use Unicode Character Set»).
Теперь компилятор будет выдавать такого рода ошибки:

И программисты начнут исправлять ошибку таким образом:

И это не усмирит компилятор, потому что конвертирование из TCHAR* в TCHAR[7] невозможно. Такая же ошибка будет возникать когда встроенные ANSI строки передаются Unicode функции:

К сожалению (или к счастью), эта ошибка может быть неправильно исправлена простым приведением типов языка C.

Строка «Saturn» это последовательность 7 байт:

‘S’ (83)‘a’ (97)‘t’ (116)‘u’ (117)‘r’ (114)‘n’ (110)‘\0’ (0)

Но когда вы передаете тот же набор байтов в wcslen, он рассматривает каждые 2 байта как один символ. Поэтому первые 2 байта [97,83] будут рассматриваться как один символ имеющий значение 24915(97

Теперь, Я надеюсь Вы понимаете следующий код:

Продолжая тему. Вы наверное видели некоторые функции/методы которым нужно передавать количество символов, или возвращающие количество символов. Впрочем есть GetCurrentDirectory, в которую надо передавать число символов, а не количество байт.
Пример:

С другой стороны, если вам нужно выделять память для нужного количества символов, вы должны выделять надлежащее количество байт. В C + +, вы можете просто использовать оператор new:

Но если вы используете функции выделения памяти, такие как malloc, LocalAlloc, GlobalAlloc, и т.д., вы должны указывать количество байт!

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

Источник

/Zc:wchar_t (wchar_t – это собственный тип)

Разбор wchar_t как встроенного типа в соответствии со стандартом C++.

Синтаксис

Комментарии

Если параметр /Zc: wchar_t имеет значение ON, то является ключевым словом встроенного целочисленного типа в коде, скомпилированном как C++. Если параметр /Zc: wchar_t- (со знаком минус) или в коде, скомпилированном как C, не является встроенным типом. Вместо этого wchar_t определяется как typedef для unsigned short в каноническом заголовке STDDEF. h. (Реализация Майкрософт определяет его в другом заголовке, который входит в состав STDDEF. h и других стандартных заголовков.)

Параметр /Zc: wchar_t включен по умолчанию в компиляциях C++ и не учитывается в компиляциях C. Параметр /permissive- не влияет на /Zc: wchar_t.

Если в коде используются глобальные функции компилятора COM, так как параметр /Zc: wchar_t теперь включен по умолчанию, рекомендуется изменить явные ссылки на комсупп. lib (из комментария pragma или в командной строке) на комсуппв. lib или комсуппвд. lib. (Если необходимо выполнить компиляцию с помощью /Zc: wchar_t-, используйте комсупп. lib.) Если включен файл заголовка comdef.h, правильная библиотека задается автоматически. Дополнительные сведения о поддержке COM компилятором см. в разделе Поддержка COM компилятором.

wchar_t Встроенный тип не поддерживается при компиляции кода на языке C. Дополнительные сведения о проблемах соответствия с Visual C++ см. в разделе нестандартное поведение.

Установка данного параметра компилятора в среде разработки Visual Studio

Откройте диалоговое окно Страницы свойств проекта. Подробнее см. в статье Настройка компилятора C++ и свойства сборки в Visual Studio.

Источник

Что именно может представлять wchar_t?

wchar_t — тип для представления широких символов (см. широкие строки). Требуется быть достаточно большим, чтобы представлять любую поддерживаемую символьную кодовую точку (32 бита в системах, поддерживающих Юникод. Заметным исключением является Windows, где wchar_t составляет 16 бит и содержит кодовые единицы UTF-16). Он имеет одинаковый размер, подпись и выравнивание. как один из целочисленных типов, но это отдельный тип.

Тип wchar_­t это отдельный тип, значения которого могут представлять различные коды для всех членов самого большого расширенного набора символов, указанного среди поддерживаемых локалей. Тип wchar_­t должны иметь те же требования к размеру, подписи и выравниванию, что и один из других интегральных типов, называемый его базовым типом. Типы char16_­t а также char32_­t обозначают различные типы с тем же размером, подписью и выравниванием, что и uint_­least16_­t а также uint_­least32_­t соответственно в называется базовыми типами.

Решение

Прежде всего, обратите внимание, что кодировка не заставляет вас использовать какой-либо конкретный тип для представления определенного символа. Вы можете использовать char представлять символы Unicode так же, как wchar_t можно — нужно только запомнить, что до 4 char s вместе образуют правильную кодовую точку в зависимости от кодировки UTF-8, UTF-16 или UTF-32, а wchar_t можно использовать 1 (UTF-32 в Linux и т. д.) или до 2, работающих вместе (UTF-16 в Windows).

Далее, нет определенной кодировки Unicode. Некоторые кодировки Unicode используют фиксированную ширину для представления кодовых точек (например, UTF-32), другие (например, UTF-8 и UTF-16) имеют переменную длину (например, буква «а», безусловно, будет использовать только 1 байт, но отдельно). от английского алфавита, другие символы обязательно будут использовать больше байтов для представления).

Таким образом, вы должны решить, какие символы вы хотите представить, и затем выбрать соответствующую кодировку. В зависимости от типа символов, которые вы хотите представить, это повлияет на количество байтов, которые будут занимать ваши данные. Например. использование UTF-32 для представления в основном английских символов приведет к большому количеству 0-байтов. UTF-8 — лучший выбор для многих латинских языков, в то время как UTF-16 обычно — лучший выбор для восточноазиатских языков.

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

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

На данный момент в Unixode есть только базовая языковая поддержка для Unicode (например, char16_t а также char32_t типы данных и u8 / u / U буквальные префиксы). Поэтому выбор библиотеки для управления кодировками (особенно преобразованиями), безусловно, хороший совет.

Другие решения

wchar_t используется в Windows, которая использует формат UTF16-LE. wchar_t требует широких функций символа Например wcslen(const wchar_t*) вместо strlen(const char*) а также std::wstring вместо std::string

Машины на основе Unix (Linux, Mac и т. Д.) Используют UTF8. Это использует char для хранения, и те же функции C и C ++ для ASCII, такие как strlen(const char*) а также std::string (см. комментарии ниже о std::find_first_of )

wchar_t это 2 байта (UTF16) в Windows. Но на других машинах это 4 байта (UTF32). Это делает вещи более запутанными.

Для UTF32 вы можете использовать std::u32string что одинаково в разных системах.

Вы можете подумать о преобразовании UTF8 в UTF32, потому что таким образом каждый символ всегда будет 4 байта, и вы можете подумать, что строковые операции будут проще. Но это редко необходимо.

Рассмотрим следующую строку UTF8. Допустим, вы хотите найти запятую

Найти 汉 Вы можете искать строку u8″汉» поскольку эта кодовая точка не может быть представлена ​​как один символ.

Некоторые функции C и C ++ не работают гладко с UTF8. Они включают

Аргументом для вышеуказанных функций является набор символов, а не фактическая строка.

Так str.find_first_of(u8″汉») не работает. Так как u8″汉» 3 байта и find_first_of будет искать любой из этих байтов. Существует вероятность того, что один из этих байтов используется для представления другой кодовой точки.

С другой стороны, str.find_first_of(u8″,;abcd») является безопасным, потому что все символы в аргументе поиска являются ASCII ( str сам может содержать любой символ Unicode)

В редких случаях может потребоваться UTF32 (хотя я не могу себе представить, где!) Вы можете использовать std::codecvt преобразовать UTF8 в UTF32 для выполнения следующих операций:

Вы должны использовать «Юникод везде», не «UTF8 везде».

В Linux, Mac и т. Д. Используйте UTF8 для Unicode.

В Windows используйте UTF16 для Unicode. Программисты Windows используют UTF16, они не делают бессмысленных преобразований туда и обратно в UTF8. Но есть законные случаи использования UTF8 в Windows.

Программист Windows, как правило, использует UTF8 для сохранения файлов, веб-страниц и т. Д. Так что для программистов, не являющихся Windows, это меньше беспокоит совместимость.

Самому языку не важно, какой формат Unicode вы хотите использовать, но с точки зрения практичности используйте формат, который соответствует системе, с которой вы работаете.

Итак, если я хочу иметь дело с символами Unicode, я должен использовать wchar_t?

Это зависит от того, с какой кодировкой вы имеете дело. В случае UTF-8 у вас все в порядке с char и std :: string.
UTF-8 означает, что наименьшая единица кодирования составляет 8 битов: все кодовые точки Unicode от U + 0000 до U + 007F кодируются только 1 байтом.
Начиная с кодовой точки U + 0080, UTF-8 использует 2 байта для кодирования, начиная с U + 0800, он использует 3 байта, а с U + 10000 4 байта.
Для обработки этой переменной ширины (1 байт — 2 байта — 3 байта — 4 байта) символ подходит лучше всего.
Имейте в виду, что C-функции, такие как strlen, будут предоставлять результаты на основе байтов: «öö» на самом деле является 2-символьным текстом, но strlen вернет 4, потому что «ö» кодируется в 0xC3B6.

UTF-16 означает, что наименьшая единица кодирования составляет 16 битов: все кодовые точки от U + 0000 до U + FFFF кодируются 2 байтами; начиная с U + 100000 используется 4 байта.
В случае UTF-16 вы должны использовать wchar_t и std :: wstring, потому что большинство символов, с которыми вы когда-либо столкнетесь, будут закодированы в 2 байта.
При использовании wchar_t вы больше не можете использовать C-функции, такие как strlen; Вы должны использовать широкие эквиваленты символов, такие как wcslen.

При использовании Visual Studio и сборке с конфигурацией «Юникод» вы получите UTF-16: TCHAR и CString будут основаны на wchar_t вместо char.

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

Основная проблема здесь не в sizeof wchar_t вы используете, но если библиотеки, которые вы собираетесь использовать, поддерживают полную поддержку юникода.

Java имеет аналогичную проблему, так как его char тип имеет ширину 16 бит, поэтому не может априори поддержка полного пространства Юникода, но оно делает, поскольку он использует кодировку UTF-16 и пару суррогатов, чтобы справиться с полными 24-битными кодовыми точками.

Стоит также отметить, что UNICODE использует только верхнюю плоскость для кодирования редких кодовых точек, которые обычно не используются ежедневно.

В любом случае, для поддержки юникода вам нужно использовать широкие наборы символов, поэтому wchar_t хорошее начало Если вы собираетесь работать с visual studio, то вам нужно проверить, как библиотеки работают с символами юникода.

Наконец, еще раз учтите, что если вы имеете дело с Microsoft Visual C ++, у вас другая реализация с самого начала. Даже если они справляются, чтобы быть полностью соответствует стандарту, вам придется справиться с некоторыми особенностями другой реализации. Возможно, у вас будут разные имена функций для некоторых целей.

Все зависит от того, что вы подразумеваете под «иметь дело», но одно можно сказать наверняка: когда речь идет о Unicode std::basic_string не предоставляет никакой реальной функциональности вообще.

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

Для поддержки этих операций почти всегда будет какая-то библиотека и / или собственный API, предоставляемый платформой, и моя цель — хранить и манипулировать моими строками таким образом, чтобы эти операции могли выполняться без разбросанных знаний о базовая библиотека и поддержка нативного API по всему коду больше, чем необходимо. Я также хотел бы рассчитывать на будущее в отношении ширины символов, которые я храню в своих строках, на случай, если я передумаю.

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

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

Потому что «abcde» является узкой строкой и различными конструкторами для std::basic_string все ожидают широкую строку. Microsoft решает это с помощью макроса ( TEXT («. «) или же __T («. «) ), но это боль. Все, что нам нужно сделать сейчас, это предоставить подходящий конструктор в MyString с подписью MyString (const char *s) и проблема решена.

На практике этот конструктор, вероятно, ожидал бы строку UTF-8, независимо от базовой ширины символа, используемой для MyString и преобразовать его при необходимости. Кто-то комментирует здесь где-то, что вы должны хранить ваши строки как UTF-8, чтобы вы могли создавать их из литералов UTF-8 в своем коде. Что ж, теперь мы нарушили это ограничение. Основная ширина символов в наших строках может быть любой, что нам нравится.

В этой теме люди говорили о том, что find_first_of может не работать должным образом со строками UTF-8 (да и вообще с некоторыми из UTF-16). Что ж, теперь вы можете предоставить реализацию, которая делает свою работу правильно. Должно занять около получаса. Если есть другие «сломанные» реализации в std::basic_string (и я уверен, что есть), тогда большинство из них, вероятно, могут быть заменены с такой же легкостью.

Или, если вам нужно передать строки UTF-16 в / из собственных API-интерфейсов Windows, вы можете добавить методы для преобразования в и из const WCHAR * (что опять-таки вы бы реализовали таким образом, чтобы они работали для всех значений mychar_t). Или вы можете пойти дальше и абстрагироваться от части или всей поддержки Unicode, предоставляемой используемой платформой и библиотекой. Mac, например, имеет богатую поддержку Unicode, но он доступен только в Objective-C, поэтому вам нужно обернуть его.
Это зависит от того, насколько переносимым должен быть ваш код.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *