Я новичок в программировании для Windows, и после прочтения книги Петцольда мне интересно:
по-прежнему ли хорошей практикой является использование типа TCHAR и функции _T() для объявления строк или мне следует просто использовать строки wchar_t и L"" в новом коде?
Я буду ориентироваться только на Windows 2000 и выше, и мой код с самого начала будет i18n.





Да, конечно; по крайней мере, для макроса _T. Однако я не уверен в том, что такое широкие символы.
Причина в том, чтобы лучше поддерживать WinCE или другие нестандартные платформы Windows. Если вы на 100% уверены, что ваш код останется на NT, вы, вероятно, можете просто использовать обычные объявления C-строки. Тем не менее, лучше иметь тенденцию к более гибкому подходу, поскольку намного проще # определить этот макрос на платформе, отличной от Windows, по сравнению с просмотром тысяч строк кода и добавлением его повсюду на случай, если вам нужно перенести какую-то библиотеку. в Windows Mobile.
Если вам интересно, используется ли он еще на практике, тогда да - он все еще используется довольно часто. Никто не посмеется над вашим кодом, если он использует TCHAR и _T (""). Проект, над которым я сейчас работаю, - это преобразование из ANSI в Unicode - и мы идем по портативному (TCHAR) маршруту.
Тем не мение...
Я бы предпочел забыть обо всех переносимых макросах ANSI / UNICODE (TCHAR, _T ("") и все вызовы _tXXXXXX и т. д.) И просто использовать Юникод везде. Я действительно не вижу смысла переноситься, если вам никогда не понадобится версия ANSI. Я бы использовал все функции и типы широких символов напрямую. Перед всеми строковыми литералами стоит буква L.
Вы можете написать какой-нибудь код, который захотите использовать где-нибудь еще, где вам действительно нужна версия ANSI, или (как сказал Ник) Windows может перейти на DCHAR или что-то еще, поэтому я все же считаю очень хорошей идеей использовать TCHAR вместо WCHAR.
Я сомневаюсь, что Windows когда-нибудь перейдет на UTF-32.
-1 для рекомендации UTF-16. Это не только создает непереносимый (ориентированный на окна) код, что неприемлемо для библиотек - хотя может использоваться для простейших случаев, таких как код пользовательского интерфейса - это неэффективно даже в самой Windows. utf8everywhere.org
Я бы все равно использовал синтаксис TCHAR, если бы сегодня делал новый проект. Практически нет большой разницы между его использованием и синтаксисом WCHAR, и я предпочитаю код, который явно указывает тип символа. Поскольку большинство функций API и вспомогательных объектов принимают / используют типы TCHAR (например, CString), имеет смысл использовать его. Кроме того, это дает вам гибкость, если вы решите использовать код в приложении ASCII в какой-то момент, или если Windows когда-либо перейдет на Unicode32 и т. д.
Если вы решите пойти по маршруту WCHAR, я буду откровенен об этом. То есть используйте CStringW вместо CString и макросы приведения при преобразовании в TCHAR (например, CW2CT).
Во всяком случае, это мое мнение.
В самом деле, это то, что по-прежнему будет работать, когда кодировка символов в конечном итоге изменится «снова».
Вы предпочитаете код, который явно указывает на тип символа, и поэтому используете тип, который иногда бывает таким, а иногда тем? Очень убедительно.
Краткий ответ: НЕТ.
Как и все другие, уже написанные, многие программисты все еще используют TCHAR и соответствующие функции. По моему скромному мнению вся концепция была плохой идеей. Обработка строки UTF-16 сильно отличается от простой обработки строки ASCII / MBCS. Если вы используете одни и те же алгоритмы / функции с обоими из них (это то, на чем основана идея TCHAR!), Вы получите очень плохую производительность в версии UTF-16, если вы делаете немного больше, чем простая конкатенация строк (например, парсинг и т. д.). Основная причина - Суррогаты.
За единственным исключением, когда В самом деле должен скомпилировать приложение для системы, не поддерживающей Unicode, я не вижу причин использовать этот багаж из прошлого в новом приложении.
Интересный факт: UTF-16 не всегда присутствовал на платформе NT. Суррогатные кодовые точки были введены в Unicode 2.0 в 1996 году, в том же году, когда был выпущен NT 4. Вплоть до IIRC (включая) Windows 2000 все версии NT использовали UCS-2, фактически подмножество UTF-16, которое предполагало, что каждый символ может быть представлен одной кодовой точкой (то есть без суррогатов).
Кстати, хотя я согласен с тем, что TCHAR больше не следует использовать, я не согласен с тем, что это была плохая идея. Я также думаю, что если вы выбираете явным образом вместо использования TCHAR, вы должны быть явным везде. Т.е. также не используйте функции с TCHAR / _TCHAR (например, _tmain) в их объявлении. Проще говоря: будьте последовательны. +1, все еще.
Это была хорошая идея, когда он был представлен, но он не должен иметь значения в новом коде.
Вы неверно представляете, для чего изначально были введены TCHAR: для облегчения разработки кода для версий Windows на базе Win 9x и Windows NT. В то время реализация UTF-16 в Windows NT была UCS-2, и алгоритмы синтаксического анализа / обработки строк были идентичными. Суррогатов не было. И даже с суррогатами алгоритмы для DBCS (единственная поддерживаемая кодировка MBCS для Windows) и UTF-16 одинаковы: в любой кодировке кодовая точка состоит из одной или двух кодовых единиц.
Предположим, я хочу использовать FormatMessage () для преобразования значения из WSAGetLastError () во что-то пригодное для печати. В документации к WSAGetLastError () говорится, что он принимает LPTSTR в качестве указателя на буфер. У меня действительно нет другого выбора, кроме как использовать TCHAR, не так ли?
@EdwardFalk: WSAGetLastError не принимает никаких аргументов, поэтому я предполагаю, что вы имеете в виду FormatMessage. Как указано в документации, существует экспорт в Unicode, FormatMessageW, для которого требуется LPWSTR. Нет необходимости использовать сопоставления универсального текста. Это верно почти для всех вызовов Windows API, которые принимают строковые аргументы.
Я должен согласиться с Сашей. Основная предпосылка TCHAR / _T() / и т. д. Состоит в том, что вы можете написать приложение на основе "ANSI", а затем волшебным образом предоставить ему поддержку Unicode, определив макрос. Но это основано на нескольких неверных предположениях:
Вы активно создаете версии своего программного обеспечения как для MBCS, так и для Unicode.
В противном случае вы ошибетесь воля и будете использовать обычные строки char* во многих местах.
Что вы не используете символы обратной косой черты, отличные от ASCII, в литералах _T ("...").
Если ваша кодировка «ANSI» не соответствует ISO-8859-1, результирующие литералы char* и wchar_t* не будут представлять одни и те же символы.
Строки UTF-16 используются так же, как строки ANSI.
Они не. Unicode вводит несколько концепций, которых нет в большинстве устаревших кодировок символов. Суррогаты. Объединение персонажей. Нормализация. Условные и зависящие от языка правила регистра.
И, возможно, самое главное, тот факт, что UTF-16 редко сохраняется на диске или отправляется через Интернет: UTF-8, как правило, предпочтительнее для внешнего представления.
Ваше приложение не использует Интернет
(Теперь это может быть допустимым предположением для программного обеспечения ваш, но ...)
Интернет работает на UTF-8 и множество более редких кодировок. Концепция TCHAR распознает только два: «ANSI» (который не могу быть UTF-8) и «Unicode» (UTF-16). Это может быть полезно для того, чтобы ваши вызовы Windows API поддерживали Unicode, но чертовски бесполезны для поддержки Unicode в ваших веб-приложениях и приложениях электронной почты.
Что вы не используете библиотеки сторонних разработчиков
Больше никто не использует TCHAR. Поко использует std::string и UTF-8. SQLite имеет версии своего API UTF-8 и UTF-16, но не TCHAR. TCHAR даже не входит в стандартную библиотеку, поэтому нет std::tcout, если вы не хотите определять его самостоятельно.
Забудьте о существовании кодировки «ANSI», за исключением тех случаев, когда вам нужно прочитать файл, который не является допустимым UTF-8. Забудьте и о TCHAR. Всегда вызывайте W-версию функций Windows API. #define _UNICODE просто для того, чтобы вы случайно не вызывали функцию «А».
Всегда используйте кодировки UTF для строк: UTF-8 для строк char и UTF-16 (в Windows) или UTF-32 (в Unix-подобных системах) для строк wchar_t. typedef Типы символов UTF16 и UTF32, чтобы избежать различий в платформах.
Звонок 2012 года: есть еще приложения, которые нужно обслуживать без #define _UNICODE даже сейчас. Конец передачи :)
@ 0xC0000022L вопрос касался кода новый. Когда вы поддерживаете старый код, вам, очевидно, придется работать в среде, для которой написан код который. Если вы поддерживаете приложение COBOL, то не имеет значения, является ли COBOL хорошим языком или нет, вы застряли на нем. И если вы поддерживаете приложение, которое полагается на TCHAR, тогда не имеет значения, было ли это хорошее решение или нет, вы застряли на нем.
Действительно, TCHAR бесполезен, кроме COBOL)
_UNICODE управляет тем, как сопоставления универсального текста разрешаются в CRT. Если вы не хотите вызывать ANSI-версию Windows API, вам необходимо определить UNICODE.
Просто добавлю к старому вопросу:
Начните новый проект CLR C++ в VS2010. Сами Microsoft используют L"Hello World", - сказал Нуфф.
Среда CLR сильно отличается от неуправляемого кода. Это аргумент нет.
Даже Microsoft делает ошибки.
-1 Вопрос помечен как C и C++. Ответы всегда могут быть удалены их соответствующими авторами. Сейчас хорошее время, чтобы воспользоваться этим положением.
Статья Введение в программирование Windows на MSDN говорит
New applications should always call the Unicode versions (of the API).
The TEXT and TCHAR macros are less useful today, because all applications should use Unicode.
Я бы придерживался wchar_t и L"".
Стивен, вы цитируете текст, написанный кем-то, кто не понимает значения слова «Юникод». Это один из тех досадных документов времен неразберихи с UCS-2.
@PavelRadzivilovsky: Документ был написан для системы, где Юникод и UTF-16LE обычно используются как взаимозаменяемые. Хотя это технически неточно, но, тем не менее, однозначно. Это также явно указано во введении к тому же тексту: «Windows представляет символы Unicode с использованием кодировки UTF-16 [...]».
IMHO, если в вашем коде есть TCHAR, вы работаете на неправильном уровне абстракции.
Использование строкового типа что бы ни наиболее удобно для вас при обработке текста - мы надеемся, что это будет что-то, поддерживающее Unicode, но это зависит от вас. При необходимости выполните преобразование на границах API ОС.
Имея дело с путями к файлам, создавайте свой собственный тип вместо использования строк. Это позволит вам использовать независимые от ОС разделители путей, даст вам более простой интерфейс для кодирования, чем ручное объединение и разделение строк, и будет намного проще адаптироваться к различным ОС (ansi, ucs-2, utf-8, что угодно) .
Unicode имеет как минимум три текущих кодировки (UTF-8, UTF-16, UTF-32) и одну устаревшую кодировку (UCS-2, подмножество того, что сейчас называется UTF-16). К какому из них вы относитесь? Мне нравятся остальные предложения, хотя +1
Единственные причины, по которым я вижу использование чего-либо, кроме явного WCHAR, - это переносимость и эффективность.
Если вы хотите, чтобы конечный исполняемый файл был как можно меньше, используйте char.
Если вас не волнует использование ОЗУ и вы хотите, чтобы интернационализация была такой же простой, как простой перевод, используйте WCHAR.
Если вы хотите сделать свой код гибким, используйте TCHAR.
Если вы планируете использовать только латинские символы, вы также можете использовать строки ASCII / MBCS, чтобы вашему пользователю не требовалось столько оперативной памяти.
Для людей, которые "i18n с самого начала", сэкономьте место для исходного кода и просто используйте все функции Unicode.
Я хотел бы предложить другой подход (ни один из двух).
Подводя итог, используйте char * и std :: string, предполагая кодировку UTF-8, и выполняйте преобразование в UTF-16 только при упаковке функций API.
Дополнительную информацию и обоснование этого подхода в программах Windows можно найти в http://www.utf8everywhere.org.
@PavelRadzivilovsky, при реализации вашего предложения в приложении VC++, установим ли мы для символа VC++ значение «None» или «Multibyte (MBCS)»? Причина, по которой я спрашиваю, заключается в том, что я только что установил Boost :: Locale, а набором символов по умолчанию был MBCS. FWIW, мое чистое приложение ASCII было установлено на «Нет», и я теперь установил его на «MBCS» (так как я буду использовать в нем Boost :: Locale), и оно работает нормально. Пожалуйста, порекомендуйте.
Как рекомендует utf8everywhere, я бы установил для него значение «Использовать набор символов Unicode». Это рекламирует дополнительную безопасность, но не требуется. Автор Boost :: locale очень умный парень, но я уверен, что он поступил правильно.
Мантра UTF-8 везде не станет правильным решением только потому, что ее повторяют чаще. UTF-8, несомненно, является привлекательной кодировкой для сериализации (например, файлов или сетевых сокетов), но в Windows часто более уместно хранить символьные данные, используя внутреннюю кодировку UTF-16, и преобразовывать на границе приложения. Одна из причин заключается в том, что UTF-16 - единственная кодировка, которая может быть немедленно преобразована в любую другую поддерживаемую кодировку. Это не относится к UTF-8.
«..UTF-16 - единственная кодировка, которая может быть немедленно преобразована в любую другую поддерживаемую кодировку». что ты имеешь в виду? В чем проблема с преобразованием кодировки UTF-8 во что-нибудь еще?
@PavelRadzivilovsky: «В чем проблема с преобразованием кодировки UTF-8 во что-нибудь еще?» - Я не это сказал. Вы можете сразу преобразовать UTF-8 в UTF-16, вызвав MultiByteToWideChar. Но вы не можете преобразовать из UTF-8 во что-либо еще без предварительного преобразования в UTF-16.
Я не понимаю. К чему-нибудь еще - какому? Например. ПСК-4? Почему нет? Кажется очень простым, полностью числовой алгоритм ..
TCHAR / WCHAR может быть достаточно для некоторых устаревших проектов. Но для новых приложений я бы сказал НЕТ.
Все эти TCHAR / WCHAR существуют по историческим причинам. TCHAR предоставляет удобный способ (маскировку) для переключения между кодировкой текста ANSI (MBCS) и кодировкой текста Unicode (UTF-16). В прошлом у людей не было представления о количестве символов всех языков мира. Они предположили, что 2 байта было достаточно для представления всех символов и, таким образом, имели схему кодирования символов фиксированной длины с использованием WCHAR. Однако это больше не так после выпуска Unicode 2.0 в 1996 г..
То есть:
Независимо от того, что вы используете в CHAR / WCHAR / TCHAR, часть обработки текста в вашей программе должна иметь возможность обрабатывать символы переменной длины для интернационализации.
Так что вам действительно нужно сделать больше, чем просто выбрать один из CHAR / WCHAR / TCHAR для программирования в Windows:
WCHAR. Так как с WinAPI так проще работать с поддержкой Unicode.Посетите этот замечательный веб-сайт для более подробного чтения: http://utf8everywhere.org/
TCHAR имеют новое значение для переноса с WCHAR на CHAR.
https://docs.microsoft.com/en-us/windows/uwp/design/globalizing/use-utf8-code-page
Recent releases of Windows 10 have used the ANSI code page and -A APIs as a means to introduce UTF-8 support to apps. If the ANSI code page is configured for UTF-8, -A APIs operate in UTF-8.
WinCE использует 16-битные строки wchar_t точно так же, как Win32. У нас есть большая база кода, работающего на WinCE и Win32, и мы никогда не используем TCHAR.