Актуален ли ТЧАР?

87

Я новичок в программировании для Windows, и после прочтения книги Петцольда мне интересно:

это еще хорошая практика , чтобы использовать TCHARтип и _T()функцию , чтобы объявить строки или если я должен просто использовать wchar_tи L""строки в новом коде?

Я буду ориентироваться только на Windows 2000 и выше, и мой код будет i18n с самого начала.

Фабио
источник

Ответы:

15

Я бы все равно использовал синтаксис TCHAR, если бы сегодня делал новый проект. Между его использованием и синтаксисом WCHAR нет большой практической разницы, и я предпочитаю код, который явно указывает тип символа. Поскольку большинство функций API и вспомогательных объектов принимают / используют типы TCHAR (например, CString), имеет смысл использовать его. Кроме того, это дает вам гибкость, если вы в какой-то момент решите использовать код в приложении ASCII, или если Windows когда-либо перейдет на Unicode32 и т. Д.

Если вы решите пойти по маршруту WCHAR, я скажу об этом прямо. То есть используйте CStringW вместо CString и макросы приведения при преобразовании в TCHAR (например, CW2CT).

Во всяком случае, это мое мнение.

Ник
источник
В самом деле, это то, что будет работать, когда кодировка символов в конечном итоге изменится «снова».
Medinoc
11
Вы предпочитаете код, который явно указывает на тип символа, и поэтому используете тип, который иногда бывает таким, а иногда тем? Очень убедительно.
Дедупликатор
4
−1 для несоответствия, отмеченного @Deduplicator, и для рекомендации по отрицательной выплате использовать макрос, который может быть любым (и обычно не будет проверяться более чем для одного конкретного значения).
Приветствия и hth. - Alf
90

Короткий ответ: НЕТ .

Как и все другие, уже написанные, многие программисты все еще используют TCHAR и соответствующие функции. По моему скромному мнению, идея в целом была плохой . Обработка строк UTF-16 сильно отличается от простой обработки строк ASCII / MBCS. Если вы используете одни и те же алгоритмы / функции с обоими из них (это то, на чем основана идея TCHAR!), Вы получите очень плохую производительность в версии UTF-16, если вы делаете немного больше, чем простая конкатенация строк (например, парсинг и т. д.). Основная причина - суррогаты .

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

Саша
источник
6
Интересный факт: UTF-16 не всегда присутствовал на платформе NT. Суррогатные кодовые точки были введены в Unicode 2.0 в 1996 году, в том же году, когда был выпущен NT 4. Вплоть до IIRC (включая) Windows 2000 все версии NT использовали UCS-2, фактически подмножество UTF-16, которое предполагало, что каждый символ может быть представлен одной кодовой точкой (т. Е. Без суррогатов).
0xC0000022L
3
кстати, хотя я согласен, что это TCHARне должно больше использоваться, я не согласен с тем, что это была плохая идея. Я также думаю, что если вы решите быть явным, а не использовать, TCHARвы должны быть явным везде . Т.е. не используйте функции с TCHAR/ _TCHAR(например, _tmain) в их объявлении. Проще говоря: будьте последовательны. +1, все еще.
0xC0000022L
3
Это была хорошая идея назад , когда она была введена, но она должна быть не имеет значения в новом коде.
Адриан Маккарти,
4
Вы искажаете то, для чего TCHARизначально были введены: Для облегчения разработки кода для версий Windows на базе Win 9x и Windows NT. В то время реализация UTF-16 в Windows NT была UCS-2, и алгоритмы синтаксического анализа / обработки строк были идентичными. Суррогатов не было. И даже с суррогатами алгоритмы для DBCS (единственная поддерживаемая кодировка MBCS для Windows) и UTF-16 одинаковы: в любой кодировке кодовая точка состоит из одной или двух кодовых единиц.
IInspectable
Предположим, я хочу использовать FormatMessage () для преобразования значения из WSAGetLastError () во что-то пригодное для печати. В документации к WSAGetLastError () говорится, что LPTSTR используется в качестве указателя на буфер. У меня действительно нет другого выбора, кроме как использовать TCHAR, не так ли?
Эдвард Фальк,
80

Я должен согласиться с Сашей. Основная предпосылка 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. Poco использует std::stringи UTF-8. SQLite имеет версии своего API UTF-8 и UTF-16, но нет TCHAR. TCHARнет даже в стандартной библиотеке, так что нет, std::tcoutесли вы не хотите определять его самостоятельно.

Что рекомендую вместо TCHAR

Забудьте о существовании кодировки "ANSI", за исключением случаев, когда вам нужно прочитать файл, который не является допустимым UTF-8. Забудь и об этом TCHAR. Всегда вызывайте W-версию функций Windows API. #define _UNICODEпросто чтобы убедиться, что вы случайно не вызываете функцию «А».

Всегда используйте кодировки UTF для строк: UTF-8 для charстрок и UTF-16 (в Windows) или UTF-32 (в Unix-подобных системах) для wchar_tстрок. typedef UTF16и UTF32типы символов, чтобы избежать различий в платформах.

dan04
источник
6
Звонок 2012 года: есть приложения, которые нужно обслуживать #define _UNICODEдаже сейчас. Конец передачи :)
0xC0000022L
12
@ 0xC0000022L вопрос был о новом коде. Когда вы поддерживаете старый код, вы, очевидно, должны работать со средой, для которой код написан. Если вы поддерживаете приложение COBOL, не имеет значения, хороший язык COBOL или нет, вы застряли на нем. И если вы поддерживаете приложение, которое полагается на TCHAR, тогда не имеет значения, было ли это хорошее решение или нет, вы застряли на нем.
jalf
2
Действительно, TCHAR бесполезен, если не используется COBOL)
Павел Радзивиловский
1
_UNICODEуправляет тем, как сопоставления универсального текста разрешаются в CRT. Если вы не хотите вызывать ANSI-версию Windows API, вам необходимо определить UNICODE.
IInspectable 06
18

Если вам интересно, используется ли он еще на практике, тогда да - он все еще используется довольно часто. Никто не посмеется над вашим кодом, если он использует TCHAR и _T (""). Проект, над которым я сейчас работаю, - это преобразование из ANSI в Unicode - и мы идем по портативному (TCHAR) маршруту.

Однако...

Я бы предпочел забыть обо всех переносимых макросах ANSI / UNICODE (TCHAR, _T ("") и все вызовы _tXXXXXX и т. Д.) И просто использовать Юникод везде. Я действительно не вижу смысла переноситься, если вам никогда не понадобится версия ANSI. Я бы использовал все функции и типы широких символов напрямую. Перед всеми строковыми литералами ставьте символ L.

Трубкозуб
источник
3
Вы можете написать какой-нибудь код, который захотите использовать где-нибудь еще, где вам действительно нужна версия ANSI, или (как сказал Ник) Windows может перейти на DCHAR или что-то еще, поэтому я все же считаю очень хорошей идеей использовать TCHAR вместо WCHAR.
arke
Я сомневаюсь, что Windows когда-нибудь перейдет на UTF-32.
dan04
7
-1 для рекомендации UTF-16. Это не только создает непереносимый (ориентированный на окна) код, что неприемлемо для библиотек - хотя может использоваться для простейших случаев, таких как код пользовательского интерфейса - это неэффективно даже в самой Windows. utf8everywhere.org
Павел Радзивиловский
11

В статье Введение в программирование Windows на MSDN говорится:

Новые приложения всегда должны вызывать версии Unicode (API).

TEXT и TCHAR макросы менее полезны сегодня, поскольку все приложения должны использовать Unicode.

Я бы придерживался wchar_tи L"".

Стивен
источник
4
Стивен, вы цитируете текст, написанный кем-то, кто не понимает значения слова «Юникод». Это один из тех досадных документов времен неразберихи с UCS-2.
Павел Радзивиловский
2
@PavelRadzivilovsky: Документ был написан для системы, в которой Unicode и UTF-16LE обычно используются как взаимозаменяемые. Хотя это технически неточно, но, тем не менее, однозначно. Это также явно указано во введении к тому же тексту: «Windows представляет символы Unicode с использованием кодировки UTF-16 [...]» .
IInspectable 02
11

Я хотел бы предложить другой подход (ни один из двух).

Подводя итог, используйте 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 очень умный парень, но я уверен, что он поступил правильно.
Павел Радзивиловский
1
UTF-8 Везде мантра не будет правильным решением, только потому , что она повторяется чаще. UTF-8, несомненно, является привлекательной кодировкой для сериализации (например, файлов или сетевых сокетов), но в Windows часто более уместно хранить символьные данные, используя внутреннюю кодировку UTF-16, и конвертировать на границе приложения. Одна из причин заключается в том, что UTF-16 - единственная кодировка, которая может быть немедленно преобразована в любую другую поддерживаемую кодировку. Это не относится к UTF-8.
IInspectable 02
«..UTF-16 - единственная кодировка, которая может быть немедленно преобразована в любую другую поддерживаемую кодировку». что вы имеете в виду? В чем проблема с преобразованием кодировки UTF-8 во что-нибудь еще?
Павел Радзивиловский
1
Я не понимаю. К чему-нибудь еще - какому? Например, UCS-4? Почему нет? Кажется, очень простой, полностью числовой алгоритм ..
Павел Радзивиловский
7

TCHAR/ WCHARможет быть достаточно для некоторых устаревших проектов. Но для новых приложений я бы сказал НЕТ .

Все эти TCHAR/ WCHARвещи есть в силу исторических причин. TCHARобеспечивает удобный способ (маскировку) переключения между кодировкой текста ANSI (MBCS) и кодировкой текста Unicode (UTF-16). В прошлом у людей не было представления о количестве символов всех языков мира. Они предположили, что 2 байта было достаточно для представления всех символов и, следовательно, с использованием схемы кодирования символов фиксированной длины WCHAR. Однако это больше не так после выпуска Unicode 2.0 в 1996 году .

То есть: независимо от того, что вы используете в CHAR/ WCHAR/ TCHAR, часть обработки текста в вашей программе должна иметь возможность обрабатывать символы переменной длины для интернационализации.

Таким образом, вам действительно нужно сделать больше, чем выбрать один из CHAR/ WCHAR/ TCHARдля программирования в Windows:

  1. Если ваше приложение маленькое и не требует обработки текста (т.е. просто передает текстовую строку в качестве аргументов), придерживайтесь WCHAR. Так как с WinAPI так проще работать с поддержкой Unicode.
  2. В противном случае я бы предложил использовать UTF-8 в качестве внутренней кодировки и хранить тексты в строках char или std :: string. И скрыть их в UTF-16 при вызове WinAPI. UTF-8 в настоящее время является доминирующей кодировкой, и существует множество удобных библиотек и инструментов для обработки строк UTF-8.

Посетите этот замечательный сайт для более подробного чтения: http://utf8everywhere.org/

LeOpArD
источник
2
«UTF-8 теперь является доминирующей кодировкой» - это оказалось неверным, поскольку вторая часть цитаты ( «для всемирной паутины» ) не использовалась. Для настольных приложений наиболее часто используемая собственная кодировка символов по-прежнему UTF-16. Его использует Windows, Mac OS X и строковые типы .NET и Java. На это приходится огромное количество кода. Не поймите меня неправильно, в UTF-8 для сериализации нет ничего плохого. Но чаще всего (особенно в Windows) вы обнаружите, что внутреннее использование UTF-16 более уместно.
IInspectable 07
4

Да, конечно; по крайней мере, для макроса _T. Однако я не уверен в том, что такое широкие символы.

Причина в том, чтобы лучше поддерживать WinCE или другие нестандартные платформы Windows. Если вы на 100% уверены, что ваш код останется на NT, вы, вероятно, можете просто использовать обычные объявления C-строки. Тем не менее, лучше иметь тенденцию к более гибкому подходу, так как намного проще # определить этот макрос на платформе, отличной от Windows, по сравнению с просмотром тысяч строк кода и добавлением его повсюду на случай, если вам нужно перенести какую-то библиотеку. в Windows Mobile.

Ник Рейман
источник
1
WinCE использует 16-битные строки wchar_t, как и Win32. У нас есть большая база кода, работающего на WinCE и Win32, и мы никогда не используем TCHAR.
mhenry1384
2

ИМХО, если в вашем коде есть TCHAR, вы работаете на неправильном уровне абстракции.

Используйте любой тип строки, наиболее удобный для вас при обработке текста - мы надеемся, что это будет что-то, поддерживающее юникод, но это зависит от вас. При необходимости выполните преобразование на границах API ОС.

Имея дело с путями к файлам, используйте свой собственный тип вместо строк. Это позволит вам использовать независимые от ОС разделители путей, даст вам более простой интерфейс для кодирования, чем ручное объединение и разделение строк, и будет намного легче адаптироваться к различным ОС (ansi, ucs-2, utf-8, что угодно) .

снемарш
источник
Unicode имеет как минимум три текущих кодировки (UTF-8, UTF-16, UTF-32) и одну устаревшую кодировку (UCS-2, подмножество того, что сейчас называется UTF-16). К какому из них вы относитесь? Однако мне нравятся остальные предложения +1
0xC0000022L
2

Единственные причины, по которым я вижу использование чего-либо, кроме явного WCHAR, - это переносимость и эффективность.

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

Если вас не волнует использование ОЗУ и вы хотите, чтобы интернационализация была такой же простой, как простой перевод, используйте WCHAR.

Если вы хотите сделать свой код гибким, используйте TCHAR.

Если вы планируете использовать только латинские символы, вы также можете использовать строки ASCII / MBCS, чтобы вашему пользователю не требовалось столько оперативной памяти.

Для людей, которые "i18n с самого начала", сэкономьте место для исходного кода и просто используйте все функции Unicode.

Трололол
источник
-1

Просто добавлю к старому вопросу:

Нет

Начните новый проект CLR C ++ в VS2010. Сами Microsoft используют L"Hello World", - сказал Нафф.

kizzx2
источник
13
CLR - это совсем другая среда, чем неуправляемый код. Это не аргумент.
Коди Грей
3
Даже Microsoft делает ошибки.
Павел Радзивиловский
6
-1 Вопрос помечен Cи C++. Ответы всегда могут быть удалены их соответствующими авторами. Сейчас подходящее время для использования этого положения.
IInspectable 03
-1

TCHARимеют новое значение для переноса с WCHARна CHAR.

https://docs.microsoft.com/en-us/windows/uwp/design/globalizing/use-utf8-code-page

В последних выпусках Windows 10 кодовая страница ANSI и API-интерфейсы -A использовались как средство для внедрения поддержки UTF-8 в приложениях. Если кодовая страница ANSI настроена для UTF-8, -A API работают в UTF-8.

OwnageIsMagic
источник