Поддержка Unicode в Windows появилась раньше, чем в большинстве других операционных систем.
Из-за этого многие проблемы, связанные с представлением символов, решались в Windows иначе, чем в других системах, разработчики которых отложили внедрение нового стандарта до лучших времен [1].
Самый важный пример: Windows использует кодировку UCS-2 для представления символов Юникода.
Он был рекомендован Консорциумом Unicode, поскольку версия 1.0 поддерживала только 65 536 символов [2].
Спустя пять лет Консорциум передумал, но к тому времени было уже поздно что-либо менять в Windows, поскольку на рынок уже были выпущены Win32s, Windows NT 3.1, Windows NT 3.5, Windows NT 3.51 и Windows 95 — все в них использовалась кодировка UCS -2 [3].
Но сегодня мы поговорим о строках формата функций.
печать .
Поскольку Unicode был принят в Windows до C, это означало, что разработчикам Microsoft пришлось придумать, как реализовать поддержку этого стандарта во время выполнения C. В результате такие функции, как wcscmp , вкшр И wprintf .
А как насчет строк формата в печать , то для них были введены следующие спецификаторы:
- %s представляет строку той же ширины, что и строка формата;
- %С представляет строку с шириной, обратной ширине строки формата;
- %хс представляет обычную строку независимо от ширины строки формата;
- %ws И %ls представляют широкую строку независимо от ширины строки формата.
И при компиляции в режиме ANSI вы получите такой результат:TCHAR buffer[256]; GetSomeString(buffer, 256); _tprintf(TEXT("The string is %s.\n"), buffer);
char buffer[256];
GetSomeStringA(buffer, 256);
printf("The string is %s.\n", buffer);
А при компиляции в режиме Unicode это выглядит так [4]:
wchar_t buffer[256];
GetSomeStringW(buffer, 256);
wprintf(L"The string is %s.\n", buffer);
Поскольку спецификатор %s принимает строку той же ширины, что и строка формата, этот код будет корректно работать как в форматах ANSI, так и в Unicode. Это решение также существенно упрощает преобразование уже написанного кода из формата ANSI в формат Unicode, поскольку вместо спецификатора %s вставляется линия необходимой ширины.
Когда поддержка Unicode была официально добавлена в C99, комитет по стандартам языка C принял другую модель строки формата для этой функции.
печать :
- %s И %хс представляют собой обычную строку;
- %ls представляет собой широкую строку.
За последние шесть лет для Windows было написано огромное количество программ объемом в миллиард строк, и они использовали старый формат. А как насчет компиляторов Visual C и C++? Было решено остаться со старой, нестандартной моделью, чтобы не сломать все существующие в мире программы Windows. Если вы хотите, чтобы ваш код работал в средах выполнения, которые следуют классическим правилам печать , а в тех, что следуют правилам стандарта C, придется ограничиться спецификаторами %хс для обычных строк и %ls для широких.
В этом случае гарантируется согласованность результатов независимо от того, передается ли в функцию строка формата.
спринтф или wsprintf .
#ifdef UNICODE
#define TSTRINGWIDTH TEXT("l")
#else
#define TSTRINGWIDTH TEXT("h")
#endif
TCHAR buffer[256];
GetSomeString(buffer, 256);
_tprintf(TEXT("The string is %") TSTRINGWIDTH TEXT("s\n"), buffer);
char buffer[256];
GetSomeStringA(buffer, 256);
printf("The string is %hs\n", buffer);
wchar_t buffer[256];
GetSomeStringW(buffer, 256);
wprintf("The string is %ls\n", buffer);
Раздельное определение ТСТРИНГВИДТ позволяет написать, например, такой код: _tprintf(TEXT("The string is ") TSTRINGWIDTH TEXT("s\n"), buffer);
Поскольку людям нравится табличное представление информации, вот таблица.
Я выделил строки со спецификаторами, которые определяются в C так же, как и в классическом формате Windows [5].
Используйте эти спецификаторы, если вы хотите, чтобы ваш код давал одинаковые результаты в обоих форматах.
Примечания [1] Казалось бы, внедрение Unicode в Windows раньше других систем должно было дать Microsoft преимущество первопроходца, но — по крайней мере в случае с Unicode — это оказалось для них «проклятием первопроходца», потому что остальные решили просто дождаться лучших времен, когда станут доступны более перспективные решения (например, кодировка UTF-8), и только потом внедрять Unicode в свои системы.
[2] Видимо считали, что 65 536 символов должно было хватить на всех .
[3] Позже он был заменен на UTF-16. К счастью, UTF-16 обратно совместим с UCS-2 для тех символов, которые могут быть представлены в обеих кодировках.
[4] Формально версия Unicode должна выглядеть так: unsigned short buffer[256];
GetSomeStringW(buffer, 256);
wprintf(L"The string is %s.\n", buffer);
Это факт wchar_t на тот момент это еще не был самостоятельный тип, и пока его не добавили в стандарт, он был всего лишь синонимом беззнаковый короткий .
О перипетиях судьбы wchar_t можно прочитать в отдельная статья .
[5] Классический формат, разработанный в Windows, появился первым, поэтому стандарту C пришлось адаптироваться к нему, а не наоборот. Примечание переводчика Я благодарен автору за эту публикацию.
Теперь становится понятно, как произошла вся эта путаница с "%s".
Дело в том, что наши пользователи постоянно задавались вопросом, почему PVS-Studio по-разному реагирует на, как им кажется, «переносимый» код, в зависимости от того, под Linux или под Windows они собирают свой проект. Необходимо сделать в описании диагностики В576 Этой теме посвящен специальный отдельный раздел (см.
«Широкие линии»).
После этой статьи все становится еще более ясным и очевидным.
Думаю, эту заметку стоит прочитать всем, кто занимается разработкой кроссплатформенных приложений.
Прочтите и расскажите своим коллегам.
Теги: #Разработка для Windows #C++ #Visual Studio #printf #si #история #история #visual c++ #Unicode #переносимость кода
-
Синхронные И Асинхронные Коммуникации
19 Oct, 24 -
Код Игры, Который Программирует Сам Себя
19 Oct, 24 -
Вывод На Вебмани С Раннера
19 Oct, 24 -
Каннские Львы – 2007.
19 Oct, 24