TCHAR是否仍然相关?


87

我是Windows编程的新手,在阅读Petzold的书后,我感到奇怪:

使用TCHAR类型和_T()函数声明字符串是否仍然是一种好习惯,或者是否应该在新代码中仅使用wchar_tandL""字符串?

我将仅针对Windows 2000及更高版本,并且从一开始我的代码就是i18n

Answers:


15

如果我今天在做一个新项目,我仍然会使用TCHAR语法。使用它和WCHAR语法之间并没有太大的实际区别,我更喜欢在字符类型上明确的代码。由于大多数API函数和辅助对象都采用/使用TCHAR类型(例如:CString),因此使用它是很有意义的。另外,如果您决定在某个时候在ASCII应用程序中使用代码,或者Windows是否进化到Unicode32等,它还为您提供了灵活性。

如果您决定采用WCHAR路线,我将对此进行明确说明。也就是说,使用CStringW而不是CString,并在转换为TCHAR时强制转换宏(例如:CW2CT)。

无论如何,这是我的看法。


实际上,当字符编码最终“再次”更改时,这仍然会起作用。
Medinoc 2014年

11
您更喜欢代码在字符类型中是明确的,因此使用的类型有时是这种,有时是那种?非常有说服力。
Deduplicator 2015年

4
-1表示@Deduplicator指出的不一致之处,并且对于否定收益建议,请使用可以为任意值的宏(并且通常不会测试一个以上的特定值)。
干杯和健康。

90

简短的回答:

像所有其他已经写过的一样,许多程序员仍在使用TCHAR和相应的功能。以我的拙见,整个概念是一个坏主意UTF-16字符串处理与简单ASCII / MBCS字符串处理有很大不同。如果您对两者使用相同的算法/函数(这是TCHAR想法所基于的!),那么,如果您要执行的操作比简单的字符串连接更多(例如,解析等)。主要原因是代理人

唯一的例外是,当您真的必须为不支持Unicode的系统编译应用程序时,我认为没有理由在新的应用程序中使用过去的包bag。


6
有趣的事实:UTF-16在NT平台上并不总是存在。替代代码点是在1996年Unicode 2.0中引入的,那是同年NT 4发布的。直到IIRC(包括Windows 2000)所有NT版本都使用UCS-2,实际上是UTF-16的子集,它假定每个字符都可以用一个代码点表示(即没有替代)。
0xC0000022L 2012年

3
顺便说一句,虽然我同意TCHAR不应再使用它,但我不同意这是一个坏主意。我还认为,如果选择显式而不是使用TCHAR,则应该在任何地方都显式。即,也不在声明中使用带有TCHAR/的函数_TCHAR(例如_tmain)。简而言之:保持一致。+1。
0xC0000022L 2012年

3
刚引入时,这是个好主意,但与新代码无关。
Adrian McCarthy

4
您可能会误称其TCHAR最初引入的目的:简化Win 9x和基于Windows NT版本的Windows的代码开发。当时,Windows NT的UTF-16实现是UCS-2,并且字符串解析/操作的算法是相同的。没有代理人。即使使用代理,DBCS(Windows唯一受支持的MBCS编码)和UTF-16的算法也相同:在两种编码中,一个代码点都包含一个或两个代码单元。
IInspectable 2015年

假设我想使用FormatMessage()将值从WSAGetLastError()转换为可打印的内容。WSAGetLastError()的文档说它将LPTSTR作为指向缓冲区的指针。除了使用TCHAR,我真的别无选择,不是吗?
爱德华·福克

80

我必须同意萨莎。的基本前提TCHAR/ _T()/等等是,你可以写一个“ANSI”为主的应用程序,然后奇迹般地通过定义一个宏给它的Unicode支持。但这是基于几个错误的假设:

您正在积极构建软件的MBCS和Unicode版本

否则,您滑倒并char*在许多地方使用普通的琴弦。

您不要在_T(“ ...”)文字中使用非ASCII反斜杠转义

除非您的“ ANSI”编码恰好是ISO-8859-1,否则结果char*wchar_t*文字将不会代表相同的字符。

UTF-16字符串的使用就像“ ANSI”字符串一样

他们不是。Unicode引入了大多数传统字符编码中不存在的几个概念。代孕 组合字符。正常化。条件和对语言敏感的大小写规则。

也许最重要的是,UTF-16很少保存在磁盘上或通过Internet发送的事实:UTF-8往往是外部表示的首选。

您的应用程序不使用互联网

(现在,这可能是软件的有效假设,但是...)

网络运行于UTF-8大量稀有编码。该TCHAR概念仅识别两个:“ ANSI”(不能为UTF-8)和“ Unicode”(UTF-16)。它可能使Windows API调用支持Unicode的功能很有用,但是它对使Web和电子邮件应用程序支持Unicode毫无用处。

您不使用非Microsoft库

没有人使用TCHARPoco使用std::string和UTF-8。 SQLite具有其API的UTF-8和UTF-16版本,但没有TCHARTCHAR甚至不在标准库中,因此std::tcout除非您想自己定义它,否则不行。

我推荐什么代替TCHAR

忘记存在“ ANSI”编码,除非您需要读取无效的UTF-8文件。也算了TCHAR。始终调用Windows API函数的“ W”版本。 #define _UNICODE只是为了确保您不会意外调用“ A”函数。

始终对字符串使用UTF编码:对于字符串,使用UTF-8;对于char字符串,使用UTF-16(在Windows上);对于字符串,使用UTF-32(在类似Unix的系统上)wchar_ttypedef UTF16UTF32字符类型,以避免平台差异。


6
2012年的呼吁:#define _UNICODE甚至到现在,仍有一些应用程序需要维护。传输结束:)
0xC0000022L 2012年

12
@ 0xC0000022L问题是关于代码。当你维护旧代码,你显然必须与环境工作代码书面。如果您要维护COBOL应用程序,那么COBOL是否是一种好语言都没关系,您一定会坚持使用它。而且,如果您要维护一个依赖于TCHAR的应用程序,那么这是否是一个好的决定都无关紧要,那么您就必须坚持下去。
2012年

2
确实,除非在COBOL中使用,否则TCHAR不会有用)
Pavel Radzivilovsky 2012年

1
_UNICODE控制如何在CRT中解析通用文本映射。如果您不想调用Windows API的ANSI版本,则需要定义UNICODE
IInspectable '16

18

如果您想知道它是否仍在实践中,那么可以-它仍然被大量使用。如果使用TCHAR和_T(“”),没有人会觉得您的代码很有趣。我现在正在处理的项目正在从ANSI转换为unicode-我们正在采用可移植(TCHAR)路线。

然而...

我的投票将是忘记所有ANSI / UNICODE可移植宏(TCHAR,_T(“”)和所有_tXXXXXX调用等),而只是在各处假设使用unicode。如果您永远不需要ANSI版本,我真的看不到可移植的意义。我会直接使用所有宽字符功能和类型。在所有字符串文字前加上L。


3
您可能会编写一些代码,想要在需要ANSI版本的其他地方使用,或者(如Nick所说)Windows可能会迁移到DCHAR或其他任何版本,所以我仍然认为与TCHAR一起使用而不是将其作为一个好主意WCHAR。
arke

我怀疑Windows是否会切换到UTF-32。
dan04 2012年

7
-1为UTF-16建议。这不仅会创建不可移植(以Windows为中心)的代码,这对于库是不可接受的-即使可能用于UI代码等最简单的情况-即使在Windows本身上,它也不是很有效。utf8everywhere.org
Pavel Radzivilovsky

11

介绍了Windows编程的文章在MSDN上说:

新应用程序应始终调用(API的)Unicode版本。

TEXTTCHAR宏是用处不大的今天,因为所有的应用程序应该使用Unicode。

我会坚持wchar_tL""


4
史蒂文(Steven),您引用的文字是由不理解“ Unicode”一词含义的人撰写的。这是UCS-2混乱时期的那些不幸文件之一。
Pavel Radzivilovsky

2
@PavelRadzivilovsky:该文档是为系统编写的,其中UnicodeUTF-16LE通常可互换使用。尽管技术上不准确,但这仍然是明确的。在同一文本的介绍中也明确指出了这一点:“ Windows使用UTF-16编码[...]表示Unicode字符”
IInspectable '16

11

我想提出一种不同的方法(两者都不适用)。

总而言之,使用char *和std :: string(假定为UTF-8编码),并且仅在包装API函数时才转换为UTF-16。

可在http://www.utf8everywhere.org中找到有关Windows程序中此方法的更多信息和理由。


@PavelRadzivilovsky,在VC ++应用程序中实现您的建议时,我们是否会将VC ++字符设置为“无”或“多字节(MBCS)”?我问的原因是我刚刚安装了Boost :: Locale,默认字符集是MBCS。FWIW,我的纯ASCII应用程序设置为“ None”,现在我将其设置为“ MBCS”(因为我将在其中使用Boost :: Locale),并且工作正常。请指教。
卡罗琳·贝尔特兰

如utf8everywhere所建议,我将其设置为“使用Unicode字符集”。这可提高安全性,但这不是必需的。Boost :: locale的作者是一个非常聪明的人,但我相信他做得正确。
Pavel Radzivilovsky

1
UTF-8无处不在的口号不会成为合适的解决方案,只是因为它是重复较多。毫无疑问,UTF-8是用于序列化的有吸引力的编码(例如文件或网络套接字),但在Windows上,通常更合适的做法是在内部使用本机UTF-16编码存储字符数据,并在应用程序边界进行转换。一个原因是,UTF-16是唯一的编码,可以立即转换为任何其他受支持的编码。UTF-8并非如此。
IInspectable '16

“ ..UTF-16是唯一的编码,可以立即转换为任何其他受支持的编码。” 你什么意思?将UTF-8编码转换为其他格式有什么问题?
Pavel Radzivilovsky '16

1
我不明白。还有什么-像什么?例如UCS-4?为什么不?看起来非常简单,所有数值算法..
Pavel Radzivilovsky

7

TCHAR/WCHAR对于某些旧项目可能就足够了。但是对于新应用,我会说“否”

所有这些TCHAR/WCHAR东东都没有因为历史的原因。TCHAR提供了一种看起来很简洁的方法(伪装),可以在ANSI文本编码(MBCS)和Unicode文本编码(UTF-16)之间进行切换。过去,人们并不了解世界上所有语言的字符数。他们假设2个字节足以表示所有字符,因此使用的固定长度字符编码方案WCHAR。但是,在1996年Unicode 2.0发布之后,情况就不再如此。

就是说:不管您在CHAR/ WCHAR/中使用哪个TCHAR,程序中的文本处理部分都应该能够处理可变长度的字符以进行国际化。

因此,除了在Windows中从CHAR/ WCHAR/中选择一项之外,您实际上还需要做更多的事情TCHAR

  1. 如果您的应用程序很小,并且不涉及文本处理(即,仅将文本字符串作为参数传递),则请坚持使用WCHAR。由于使用Unicode支持的WinAPI更容易使用这种方式。
  2. 否则,我建议使用UTF-8作为内部编码,并将文本存储在char字符串或std :: string中。并在调用WinAPI时将它们隐藏为UTF-16。UTF-8现在是主要的编码方式,并且有许多方便的库和工具可以处理UTF-8字符串。

请访问这个精彩的网站,以进行更深入的阅读:http : //utf8everywhere.org/


2
“ UTF-8现在是主要的编码” -通过省略引号的第二部分(“用于万维网”),这变成了错误。对于桌面应用程序,最常用的本机字符编码可能仍是UTF-16。Windows使用它,Mac OS X也使用它,.NET和Java的字符串类型也是如此。那占了大量的代码。不要误会我的意思,用于序列化的UTF-8没错。但是,您经常会发现(尤其是在Windows上)内部使用UTF-16更为合适。
IInspectable '16

4

是的,一点没错; 至少对于_T宏。不过,我不确定宽字符的内容。

原因是为了更好地支持WinCE或其他非标准Windows平台。如果您100%确定您的代码将保留在NT上,则可以只使用常规的C字符串声明。但是,最好趋向于更灵活的方法,因为与在非Windows平台上#define宏相比,要遍历数千行代码并将其添加到任何地方(如果需要移植某些库)要容易得多到Windows Mobile。


1
WinCE与Win32一样使用16位wchar_t字符串。我们有大量的代码可以在WinCE和Win32上运行,并且从不使用TCHAR。
mhenry1384 2010年

2

恕我直言,如果您的代码中包含TCHAR,说明您使用的是错误的抽象级别。

在处理文本处理时,请使用对您而言最方便的任何字符串类型-希望这会支持unicode,但这取决于您。根据需要在OS API边界进行转换。

处理文件路径时,请使用自己的自定义类型,而不要使用字符串。这将允许您独立于OS的路径分隔符,与手动的字符串连接和拆分相比,将使您更容易针对代码进行交互的界面,并且将更易于适应不同的OS(ansi,ucs-2,utf-8等)。 。


Unicode至少具有三种当前编码(UTF-8,UTF-16,UTF-32)和一种不推荐使用的编码(UCS-2,是现在的UTF-16的子集)。您指的是哪一个?我喜欢其余的建议,虽然+1
0xC0000022L 2012年

2

我看到使用除显式WCHAR以外的任何内容的唯一原因是可移植性和效率。

如果要使最终可执行文件尽可能小,请使用char。

如果您不关心RAM的使用,并且希望国际化像简单的转换一样容易,请使用WCHAR。

如果要使代码灵活,请使用TCHAR。

如果仅计划使用拉丁字符,则最好使用ASCII / MBCS字符串,这样您的用户就不需要那么多的RAM。

对于“从一开始就是i18n”的人,请节省自己的源代码空间,并只需使用所有Unicode函数。


-1

只是添加一个老问题:

没有

在VS2010中开始一个新的CLR C ++项目。微软自己使用L"Hello World"


13
CLR与非托管代码的环境非常不同。那不是争论。
科迪·格雷

3
甚至微软也会犯错。
Pavel Radzivilovsky

6
-1的问题是标签CC++。答案始终可以由其各自的作者删除。这将是使用该规定的好时机。
IInspectable

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.