-
_T() 和_L() _TEXT __T,L差别与接洽详解
添加时间:2013-5-17 点击量:_T() 和_L() _TEXT __T,L差别与接洽详解
_T()是一个宏,他的感化是让你的法度支撑Unicode编码
因为Windows应用两种字符集ANSI和UNICODE,
前者就是凡是应用的单字节体式格式,
但这种体式格式处理惩罚象中文如许的双字节字符不便利,
轻易呈现半个汉字的景象。
而后者是双字节体式格式,便利处理惩罚双字节字符。
Windows NT的所有与字符有关的函数都供给两种体式格式的版本,而Windows 9x只支撑ANSI体式格式。
若是你编译一个法度为ANSI体式格式,
_T实际不起任何感化。
而若是编译一个法度为UNICODE体式格式,则编译器会把Hello字符串以UNICODE体式格式保存。_T和_L的差别在于,_L不管你是以什么体式格式编译,一律以UNICODE体式格式保存。
若是是UNICODE
#define __TEXT(quote) L##quote
#define __T(x) L##x
不然
#define __TEXT(quote) quote
#define __T(x) x
在TCHAR.h
#define _T(x) __T(x)
#define _TEXT(x) __T(x)LHello! ----- 引号前面的大写字母L(代表「long」)。这将告诉编译器该字串按宽字符保存——即每个字符占用2个字节。则字串变量须要14个字节-每个字符须要2个字节,末尾的0还须要2个字节。////////////////////////////////////////////////////size_t,__T,_T,TEXT,_TEXT等一些特别宏的懂得
Unicode解决规划
对于wchar_t在WCHAR.h中是如许定义的:
#define unsigned short wchar_t
那么如今你该懂得它了吧。是以,wchar_t数据型态与无符号短整数型态雷同,都是16位宽。
要定义包含一个宽字符的变量,可应用下面的语句:
wchar_t c = A ;
变量c是一个双字节值0 x0041,是Unicode默示的字母A。(然而,因为Intel微处理惩罚器从小字节开端储存多字节数值,该字节实际上是以0 x41、0 x00的次序保存在内存中。若是搜检Unicode文字的策画机储存应重视这一点。)您还可定义指向宽字符串的指针:
wchar_t p = LHello! ;
重视紧接在第一个引号前面的大写字母L(代表「long」)。这将告诉编译器该字符串按宽字符保存-即每个字符占用2个字节。凡是,指针变量p要占用4个字节,而字符串变量须要14个字节-每个字符须要2个字节,末尾的0还须要2个字节。同样,您还可以用下面的语句定义宽字符数组:
static wchar_t a[] = LHello! ;
该字符串也须要14个字节的储存空间,sizeof (a) 将返回14。索引数组a可获得零丁的字符。a[1] 的值是宽字符「e」,或者0 x0065。固然看上去更像一个印刷符号,但第一个引号前面的L很是首要,并且在两个符号之间必须没有空格。只有带有L,编译器才知道您须要将字符串存为每个字符2字节。稍后,看到应用宽字符串而不是变量定义时,您还会碰到第一个引号前面的L。荣幸的是,若是忘怀了包含L,C编译器凡是会给提出警告或错误信息。
您还可在单个字符文字前面应用L前缀,来默示它们应申明为宽字符。如下所示:
wchar_t c = LA ;
但凡是这是不须要的,C编译器会对该字符进行扩充,使它成为宽字符。宽字符链接库函数
我们都知道如何获得字符串的长度。例如,若是我们已经像下面如许定义了一个字符串指针:char pc = Hello! ;
我们可以呼唤iLength = strlen (pc) ;
这时变量iLength将便是6,也就是字符串中的字符数。太好了!如今让我们试着定义一个指向宽字符的指针:
wchar_t pw = LHello! ;
再次呼唤strlen :iLength = strlen (pw) ;
如今麻烦来了。起首,C编译器会显示一条警告消息,可能是如许的内容:function : incompatible types - unsigned short to const char
这条消息的意思是:声明strlen函数时,该函数应接管char类型的指标,但它如今却接管了一个unsigned short类型的指标。您仍然可编译并履行该法度,但您会发明iLength便是1。为什么?
字符串「Hello!」中的6个字符占用16位:
0 x0048 0 x0065 0 x006C 0 x006C 0 x006F 0 x0021
Intel处理惩罚器在内存中将其存为:48 00 65 00 6C 00 6C 00 6F 00 21 00
假定strlen函数正试图获得一个字符串的长度,并把第1个字节作为字符开端计数,但接着假定若是下一个字节是0,则默示字符串停止。这个小操练清楚地说了然C说话本身和履行时代链接库函数之间的差别。编译器将字符串LHello! 申明为一组16位短整数型态数据,并将其保存在wchar_t数组中。编译器还处理惩罚数组索引和sizeof操纵符,是以这些都能正常工作,但在贯穿连接时才添加履行时代链接库函数,例如strlen。这些函数认为字符串由单字节字符构成。碰到宽字符串时,函数就不像我们所那样履行了。
您可能要说:「噢,太麻烦了!」如今每个C说话链接库函数都必须重写以接管宽字符。但事实上并不是每个C说话链接库函数都须要重写,只是那些有字符串参数的函数才须要重写,并且也不消由您来完成。它们已经重写完了。
strlen函数的宽字符版是wcslen(wide-character string length:宽字符串长度),并且在STRING.H(此中也说了然strlen)和WCHAR.H中均有申明。strlen函数申明如下:
size_t __cdecl strlen (const char ) ;
而wcslen函数则申明如下:size_t __cdecl wcslen (const wchar_t ) ;
这时我们知道,要获得宽字符串的长度可以呼唤iLength = wcslen (pw) ;
函数将返回字符串中的字符数6。请记住,改成宽字节后,字符串的字符长度不改变,只是位组长度改变了。您熟悉的所有带有字符串参数的C履行时代链接库函数都有宽字符版。例如,wprintf是printf的宽字符版。这些函数在WCHAR.H和含有标准函数申明的表头文件中申明。
保护单一原始码
当然,应用Unicode也有毛病。第一点也是最首要的一点是,法度中的每个字符串都将占用两倍的储存空间。此外,您将发明宽字符履行时代链接库中的函数比常规的函数大。出于这个原因,您也许想建树两个版本的法度-一个处理惩罚ASCII字符串,另一个处理惩罚Unicode字符串。好的解决办法是保护既能按ASCII编译又能按Unicode编译的单一原始码文件。固然只是一小段法度,但因为履行时代链接库函数有不合的名称,您也要定义不合的字符,这将在处理惩罚前面有L的字符串文字时碰到麻烦。
一个办法是应用Microsoft Visual C++包含的TCHAR.H表头文件。该表头文件不是ANSI C标准的一项目组,是以那边定义的每个函数和宏定义的前面都有一条底线。TCHAR.H为须要字符串参数的标准履行时代链接库函数供给了一系列的调换名称(例如,_tprintf和_tcslen)。有时这些名称也称为「通用」函数名称,因为它们既可以指向函数的Unicode版也可以指向非Unicode版。
若是定义了名为_UNICODE的标识符,并且法度中包含了TCHAR.H表头文件,那么_tcslen就定义为wcslen:
#define _tcslen wcslen
若是没有定义UNICODE,则_tcslen定义为strlen:#define _tcslen strlen
等等。TCHAR.H还用一个新的数据型态TCHAR来解决两种字符数据型态的题目。若是定义了_UNICODE标识符,那么TCHAR就是wchar_t:typedef wchar_t TCHAR ;
不然,TCHAR就是Char:typedef char TCHAR ;
如今开端评论辩论字符串文字中的L题目。若是定义了_UNICODE标识符,那么一个称作__T的宏就定义如下:#define __T(x) L##x
这是相当晦涩的语法,但合乎ANSI C标准的前置处理惩罚器规范。那一对井字号称为「粘贴符号(token paste)」,它将字母L添加到宏参数上。是以,若是宏参数是Hello!,则L##x就是LHello!。若是没有定义_UNICODE标识符,则__T宏只简单地定义如下:
#define __T(x) x
此外,还有两个宏与__T定义雷同:#define _T(x)__T(x)
#define _TEXT(x)__T(x)
在Win32 console法度中应用哪个宏,取决于您喜好简洁还是具体。根蒂根基地,必须按下述办法在_T或_TEXT宏内定义字符串文字:_TEXT (Hello!)
如许做的话,若是定义了_UNICODE,那么该串将申明为宽字符的组合,不然申明为8位的字符字符串。宽字符和 Windows
Windows NT从底层增援Unicode。这意味着Windows NT内部应用由16位字符构成的字符串。因为世界上其它很多处所还不应用16位字符串,所以Windows NT必须经常将字符串在操纵体系内转换。Windows NT可履行动ASCII、Unicode或者ASCII和Unicode混淆编写的法度。即,Windows NT支撑不合的API函数呼唤,这些函数接管8位或16位的字符串(我们将即速看到这是如何动作的。)相对于Windows NT,Windows 98对Unicode的支撑要少得多。只有很少的Windows 98函数呼唤支撑宽字符串(这些函数列在《Microsoft Knowledge Base article Q125671》中;它们包含MessageBox)。若是要发行的法度中只有一个.EXE文件请求在Windows NT和Windows 98下都能履行,那么就不该该应用Unicode,不然就不克不及在Windows 98下履行;尤其法度不克不及呼唤Unicode版的Windows函数。如许,将来发行Unicode版的法度时会处于更有利的地位,您应试着编写既为ASCII又为Unicode编译的原始码。这就是本书中所有法度的编写体式格式。
Windows表头文件类型
正如您在第一章所看到的那样,一个Windows法度包含表头文件WINDOWS.H。该文件包含很多其它表头文件,包含WINDEF.H,该文件中有很多在Windows中应用的根蒂根基型态定义,并且它本身也包含WINNT.H。WINNT.H处理惩罚根蒂根基的Unicode支撑。WINNT.H的前面包含C的表头文件CTYPE.H,这是C的浩繁表头文件之一,包含wchar_t的定义。WINNT.H定义了新的数据型态,称作CHAR和WCHAR:
typedef char CHAR ;
typedef wchar_t WCHAR ; // wc
当您须要定义8位字符或者16位字符时,推荐您在Windows法度中应用的数据型态是CHAR和WCHAR。WCHAR定义后面的注释是匈牙利标识表记标帜法的建议:一个基于WCHAR数据型态的变量可在前面附加上字母wc以申明一个宽字符。WINNT.H表头文件进而定义了可用做8位字符串指针的六种数据型态和四个可用做const 8位字符串指针的数据型态。这里精选了表头文件中一些实用的申明数据型态语句:
typedef CHAR PCHAR, LPCH, PCH, NPSTR, LPSTR, PSTR ;
typedef CT CHAR LPCCH, PCCH, LPCSTR, PCSTR ;
前缀N和L默示「near」和「long」,指的是16位Windows中两种大小不合的指标。在Win32中near和long指标没有差别。类似地,WINNT.H定义了六种可作为16位字符串指针的数据型态和四种可作为const 16位字符串指针的数据型态:
typedef WCHAR PWCHAR, LPWCH, PWCH, NWPSTR, LPWSTR, PWSTR ;
typedef CT WCHAR LPCWCH, PCWCH, LPCWSTR, PCWSTR ;
至此,我们有了数据型态CHAR(一个8位的char)和WCHAR(一个16位的wchar_t),以及指向CHAR和WCHAR的指标。与TCHAR.H一样,WINNT.H将TCHAR定义为一般的字符类型。若是定义了标识符UNICODE(没有底线),则TCHAR和指向TCHAR的指标就分别定义为WCHAR和指向WCHAR的指标;若是没有定义标识符UNICODE,则TCHAR和指向TCHAR的指标就分别定义为char和指向char的指标:#ifdef UNICODE
typedef WCHAR TCHAR, PTCHAR ;
typedef LPWSTR LPTCH, PTCH, PTSTR, LPTSTR ;
typedef LPCWSTR LPCTSTR ;
#else
typedef char TCHAR, PTCHAR ;
typedef LPSTR LPTCH, PTCH, PTSTR, LPTSTR ;
typedef LPCSTR LPCTSTR ;
#endif
若是已经在某个表头文件或者其它表头文件中定义了TCHAR数据型态,那么WINNT.H和WCHAR.H表头文件都能防止其反复定义。不过,无论何时在法度中应用其它表头文件时,都应在所有其它表头文件之前包含WINDOWS.H。WINNT.H表头文件还定义了一个宏,该宏将L添加到字符串的第一个引号前。若是定义了UNICODE标识符,则一个称作 __TEXT的宏定义如下:
#define __TEXT(quote) L##quote
若是没有定义标识符UNICODE,则像如许定义__TEXT宏:#define __TEXT(quote) quote
此外, TEXT宏可如许定义:#define TEXT(quote) __TEXT(quote)
这与TCHAR.H中定义_TEXT宏的办法一样,只是不必费神底线。我将在本书中应用这个宏的TEXT版本。这些定义可使您在同一法度中混淆应用ASCII和Unicode字符串,或者编写一个可被ASCII或Unicode编译的法度。若是您明白定义8位字符变量和字符串,请应用CHAR、PCHAR(或者其它),以及带引号的字符串。为明白地应用16位字符变量和字符串,请应用WCHAR、PWCHAR,并将L添加到引号前面。对于是8位还是16位取决于UNICODE标识符的定义的变量或字符串,要应用TCHAR、PTCHAR和TEXT宏。
-----------------------保护单一原始码
应用Unicode最首要毛病是,法度中的每个字串都将占用两倍的储存空间。此外,宽字符履行时代法度库中的函数比常规的函数大。是以,就有须要建树两个版本的法度——一个处理惩罚ASCII字串,另一个处理惩罚Unicode字串。好的解决办法是保护既能按ASCII编译又能按Unicode编译的单一原始码档案。一个办法是应用Microsoft Visual C++包含的TCHAR.H头文件。(该头文件不是ANSI C标准的一项目组,是以此中定义的每个函数和巨集定义的前面都有一条下横线。)TCHAR.H为须要字串参数的标准履行时代法度库函数供给了一系列的调换名称(例如,_tprintf和_tcslen)。有时这些名称也称为「通用」函数名称,因为它们既可以指向函数的Unicode版也可以指向非Unicode版。若是定义了名为_UNICODE的辨认字,并且法度中包含了TCHAR.H头文件,那么_tcslen就定义为wcslen:#define _tcslen wcslen若是没有定义UNICODE,则_tcslen定义为strlen:#define _tcslen strlen等等。TCHAR.H还用一个新的数据类型TCHAR来解决两种字符数据类型的题目。若是定义了 _UNICODE辨认字,那么TCHAR就是wchar_t:typedef wchar_t TCHAR ;不然,TCHAR就是char:typedef char TCHAR ;如今开端评论辩论字串文字中的L题目。若是定义了_UNICODE辨认字,那么一个称作__T的巨集就定义如下:#define __T(x) L##x这是相当晦涩的语法,但合乎ANSI C标准的前置处理惩罚器规范。那一对井字号称为「粘贴符号(token paste)」,它将字母L添加到巨集引数上。是以,若是巨集引数是Hello!,则L##x就是LHello!。若是没有定义_UNICODE辨认字,则__T巨集只简单地定义如下:#define __T(x) x此外,还有两个巨集与__T定义雷同:#define _T(x) __T(x)#define _TEXT(x) __T(x)在Win32 console法度中应用哪个巨集,取决於您喜好简洁还是具体。根蒂根基地,必须按下述办法在_T或_TEXT巨集内定义字串文字:_TEXT (Hello!)如许做的话,若是定义了_UNICODE,那么该串将申明为宽字符的组合,不然申明为8位元的字符字串。
(转自:http://wwboss.blog.sohu.com/14019890.html)