Типы данных, определенные в Windows для Unicode
Юникод
Кодировка - способ представления в памяти компьютера цифр, буков и всех остальных знаков. Например, пробел представляется как 0b100000 (в двоичной), 32 (в десятичной) или 0x20 (в шестнадцатеричной системе счисления).
Так вот, когда-то памяти было совсем немного и всем компьютерам было достаточно 7 бит для представления всех нужных символов (цифры, строчный\прописной латинский алфавит, куча знаков и так называемые управляемые символы — все возможные 127 номеров были кому-то отданы). Кодировка в это время была одна — ASCII. Шло время, все были счастливы, а кто не был счастлив (читай — кому не хватало знака "©" или родной буквы «щ») — использовали оставшиеся 128 знаков на свое усмотрение, то есть создавали новые кодировки. Так появились и ISO-8859-1, и наши (то есть кириличные) cp1251 и KOI8. Вместе с ними появилась и проблема интерпретации байтов типа 0b1******* (то есть символов\чисел от 128 и до 255) — например, 0b11011111 в кодировке cp1251 это наша родная «Я», в тоже время в кодировке ISO-8859-1 это греческая "ß". Ожидаемо, сетевая коммуникация и просто обмен файлами между разными компьютерами превратились в чёрт-знает-что, несмотря на то, что заголовки типа 'Content-Encoding' в HTTP протоколе, email-письмах и HTML-страницах немного спасали ситуацию.
В этот момент собрались светлые умы и предложили новый стандарт — Unicode. Это именно стандарт, а не кодировка — сам по себе Юникод не определяет, как символы будут сохранятся на жестком диске или передаваться по сети. Он лишь определяет связь между символом и некоторым числом, а формат, согласно с которым эти числа будут превращаться в байты, определяется Юникод-кодировками (например, UTF-8 или UTF-16). На данный момент в Юникод-стандарте есть немного более 100 тысяч символов, тогда как UTF-16 позволяет поддерживать более одного миллиона (UTF-8 — и того больше).
Настоящей проблемой при локализации всегда были операции с различными наборами символов. Годами, кодируя текстовые строки как последовательности однобайтовых символов с нулем в конце, большинство программистов так к этому привыкло, что это стало чуть ли не второй их натурой. Вызываемая нами функция strlen возвращает количество символов в заканчивающемся нулем массиве однобайтовых символов. Но существуют такие языки и системы письменности (классический пример — японские иероглифы), в которых столько знаков, что одного байта, позволяющего кодировать не более 256 символов, просто недостаточно. Для поддержки подобных языков были созданы двухбайтовые наборы символов (double-byte character sets, DBCS).
Одно- и двухбайтовые наборы символов
В двухбайтовом наборе символ представляется либо одним, либо двумя байтами. Так, для японской каны, если значение первого байта находится между 0x81 и 0x9F или между 0xE0 и 0xFC, надо проверить значение следующего байта в строке, чтобы определить полный символ. Работа с двухбайтовыми наборами символов — просто кошмар для программиста, так как часть их состоит из одного байта, а часть — из двух.
Простой вызов функции strlen не дает количества символов в строке — она возвращает только число байтов. В ANSI-библиотске С нет функций, работающих с двухбайтовыми наборами символов. Но в аналогичную библиотеку Visual C++ включено множество функций (типа _mbslen), способных оперировать со строками мультибайтовых (как одно-, так и двухбайтовых) символов.
Для работы с DBCS-строками в Windows предусмотрен целый набор вспомогательных функций:
Функция
| Описание
| PTSTR CharNext (PCTSTR pszCurrentChar);
| Возвращает адрес следующего символа в строке
| PTSTR CharPrep(PCTSTR pszStart, PCTSTR pszCurrentChar);
| Возвращает адрес предыдущего символа в строке
| BOOL IsDBCSLeadByte (BYTE bTestChar);
| Возвращает TRUE, если данный байт — первый в DBCS-символе
| Функции CharNext и CharPrev появоляют «перемещаться» по двухбайтовой строке единовременно на 1 символ вперед или назад, a IsDBCSLeadByte возвращает TRUE, если переданный ей байт — первый в двухбайтовом символе
Хотя эти функции несколько облегчают работу с DBCS-строками, необходимость в ином подходе очевидна. Перейдем к Unicode
Unicode: набор широких символов
Unicode — стандарт, первоначально разработанный Apple и Xerox в 1988 г В 1991 г был создан консорциум для совершенствования и внедрения Unicode В него вошли компании Apple, Compaq, Hewlett-Packard, IBM, Microsoft, Oracle, Silicon Graphics, Sybase, Unisys и Xcrox.
Строки в Unicode просты и логичны. Все символы в них представлены 16-битными значениями (по 2 байта на каждый). В них нет особых байтов, указывающих, чем является следующий байт — частью того же символа или новым символом. Это значит, что прохождение по строке реализуется простым увеличением или уменьшением значения указателя. Функции CharNext, CharPrev и lsDBCSLeadByte больше не нужны.
Так как каждый символ — 16-битное число, Unicode позволяет кодировать 65 536 символов, что более чем достаточно для работы с любым языком. Разительное отличие от 256 знаков, доступных в однобайтовом наборе!
В настоящее время кодовые позиции определены для арабского, китайского, греческого, еврейского, латинского (английского) алфавитов, а также для кириллицы (русского), японской каны, корейского хантыль и некоторых других алфавитов, Кроме того, в набор символов включено большое количество знаков препинания, математических и технических символов, стрелок, диакритических и других знаков. Все вместе они занимают около 35 000 кодовых позиций, оставляя простор для будущих расширений
Эти 65 536 символов разбиты на отдельные группы Некоторые группы, а также включенные в них символы показаны в таблице
16-битный код
| Символы
| 16-битный код
| Символы
| 0000-007F
| ASCII
| 0300-U36F
| Общие диакритические
| 0080-00FF
| Символы Latin 1
| 0400-04FF
| Кириллица
| 0100-017F
| Европейские латинские
| 0530-058F
| Армянский
| 01 80-01FF
| Расширенные латинские
| 0590-05FF
| Еврейский
| 0250-02AF
| Стандартные фонетические
| 0600-06FF
| Арабский
| 02BO-02FF
| Модифицированные литеры
| 0900-097F
| Деванагари
| Около 29 000 кодовых позиций пока не заняты, но зарезервированы на будущее. Примерно 6 000 позиций оставлено специально для программистов (на их усмотрение).
Microsoft разработала Windows API так, чтобы как можно меньше влиять на Ваш код. В самом деле, у Вас появилась возможность создать единственный файл с исходным кодом, компилируемый как с применением Unicode, так и без него, — достаточно определить два макроса (UNICODE и _UNICODE), которые отвечают за нужные изменения.
Unicode и библиотека С
Для использования Unicode-строк были введены некоторые новые типы данных. Стандартный заголовочный файл String.h модифицирован в нем определен wchar_t — тип данных для Unicode-символа
typedef unsigned short wchar_t
Если Вы хотите, скажем, создать буфер для хранения Unicode-строки длиной до 99 символов с нулевым символом в конце, поставьте оператор:
wchar_t szBuffer[100];
Он создает массив из ста 16-битных значений. Конечно, стандартные функции библиотеки С для работы со строками вроде strcpy, strchr и strcat оперируют только с ANSI-строками — они не способны корректно обрабатывать Unicode-строки. Поэтому в ANSI С имеется дополнительный набор функций. Ниже приведен список строковых функций ANSI C и эквивалентных им Unicode-функций:
char * strcat(char *, const char *); wchar_t * wcscat(wchar_t *, const wchar t *); char * strchr(const char *, int); wchar_t * wcschr(const wchar_t *, wchar_t); int strcmp(const char *, const char *); int wcscmp(const wchar_t *, const wchar_t *); char * strcpy(char *, const char *); wchar_t * wcscpy(wchar_t *, const wchar_t *); size_t strlen(const char *); size_t wcslen(const wchar_t *);
Обратите внимание, что имена всех новых функций начинаются с wcs — это аббревиатура wide character set (набор широких символов) Таким образом, имена Unicode-функций образуются простой заменой префикса str соответствующих ANSI-функций на wcs.
Код, содержащий явные вызовы str- или wcs-функций, просто так компилировать с использованием и ANSI, и Unicode нельзя. Чтобы реализовать возможность компиляции "двойного назначения", замените в своей программе заголовочный файл String.h на TChar.h Он помогает создавать универсальный исходный код, способный задействовать как ANSI, так и Unicode, — и это единственное, для чего нужен файл TChar.h. Он состоит из макросов, заменяющих явные вызовы str- или wcs-функций. Если при компиляции исходного кода Вы определяете _UNICODE, макросы ссылаются на wcs-функции, а в его отсутствие — на str-фупкции
Например, в TChar.h есть макрос _tcscpy. Если Вы включили этот заголовочный файл, но UNlCODE не определен, _tcscpy раскрывается в ANSI-функцию strcpy, а если _UNICODE определен — в Unicode-функцию wcscpy, В файле TChar.h определены универсальные макросы для всех стандартных строковых функций С. При использовании этих макросов вместо конкретных имен ANSI- или Unicode-функций Ваш код можно будет компилировать в расчете как на Unicode, так и на ANSI.
Но, к сожалению, это ещe не все. В файле TChar.h есть дополнительные макросы.
Чтобы объявить символьный массив универсального назначения" (ANSI/Unicode), применяется тип данных TCHAR. Если _UNICODE определен, TCHAR объявляется так:
typedef wchar_L TCHAR;
А если UNICODE не определен, то:
typedef char TCHAR
Используя этот тип данных, можно объявить строку символов как:
TCHAR szString[100];
Можно также определять указатели на строки:
TCHAR *szError = "Error";
Правда, в этом операторе есть одна проблема. По умолчанию компилятор Microsoft С++ транслирует строки как состоящие из символов ANSI, а не Unicode. B итоге этот оператор нормально компилируется, если UNICODE не определен, но в ином случае дает ошибку. Чтобы компилятор сгенерировал Unicode-, a не ANSI-строку, оператор надо переписать так
TCHAR *szFrror = L"Error";
Заглавная буква L перед строковым литералом указывает компилятору, что его надо обрабатывать как Unicode-строку. Тогда, размещая строку в области данных программы, компилятор вставит между всеми символами нулевые байты. Но возникает другая проблема — программа компилируется, только если _UNICODE определен Следовательно, нужен макрос, способный избирательно ставить L перед строковым литералом. Эту работу выполняет макрос TEXT, также содержащийся в Tchar.h. Если _UNICODE определен, TEXT определяется как
#define TEXT(x) L ## x
В ином случае TEXT определяется следующим образом:
#define TEXT(x) x
Используя этот макрос, перепишем злополучный оператор так, чтобы его можно было корректно компилировать независимо от того, определен _UNICODE или нет:
TCHAR *szError = TEXT("Error");
Макрос TEXT применяется и для символьных литералов. Например, чтобы проверить, является ли первый символ строки заглавной буквой J:
if (szError[0] == TEXT('J')) { // первый символ - J } else { // первый символ - не J }
Типы данных, определенные в Windows для Unicode
В заголовочных файлах Windows определены следующие типы данных.
Тип данных
| Описание
| WCHAR
| Unicode-символ
| PWSTR
| Указатель на Unicode –строку
| PCWSTR
| Указатель на стоковую константу в Unicode
| Эти типы данных относятся исключительно к символам и строкам в кодировке Unicode. B заголовочных файлах Windows определены также универсальные (ANSI) Unicode) типы данных PTSTR и PCTSTR, указывающие — в зависимости от того, определен ли при компиляции макрос UNICODE, — на ANSI или на Unicode-строку
Кстати, на этот раз имя макроса UNICODE не предваряется знаком подчеркивания Дело в том, что макрос _UNICODE используется в заголовочных файлах библиотеки С, а макрос UNICODE — в заголовочных файлах Windows Для компиляции модулей исходного кода обычно приходится определять оба макроса.
Например, существует две функции CreateWindowEx: одна принимает строки в Umcode, другая — в ANSI, но прототипы этих функций чуть-чуть отличаются
HWND WINAPI CreateWindowExW( DWORD dwExStyle, PCWSTR pClassName, PCWSTR pWindowName, DWORD dwStyle, int X, int Y, int nWidth, int nHeight, HWND hWndParent, HMENU hHenu, HINSTANCE hInstance, PVOID pParam);
HWND WINAPI CreatcWindowExA( DWORD dwExStyle, PCSTR pClassName, PCSTR pWindowName, DWORD dwStyle, int X int Y, int nWidth, inT nHeight, HWND hWndParent, HMENU hMenu, HINSTANCF hInstance, PVOID pParam);
Не нашли, что искали? Воспользуйтесь поиском по сайту:
©2015 - 2024 stydopedia.ru Все материалы защищены законодательством РФ.
|