TCHAR, WCHAR, LPSTR, LPWSTR, LPCTSTR究竟是神马!!!<一>
许多Windows平台上的 c++猿友常常困惑于一些奇怪的数据类型的定义,如:TCHAR、LPCTSTR...,我在此简单说明下。
一般来说,一个字符能用一个或两个字节来存储。我们称一个字节保存的字符为ANSI字符----所有的英文字符都是这种编码。而称两个字节保存的字符为Unicode,这是包括了世界上所有语言的编码方式。VC++编译器分别使用char和wchar_t来支持ANSI和Unicode字符集。尽管对Unicode有更具体的定义,但是为了便于理解,假定它是两字节的字符。(注:Windows不仅仅只使用2字节来表示Unicode字符集,而使用UTF-16字符编码)
如果你想要你的c/c++代码独立于字符集,该如何做呢?建议:使用通用数据类型和名称来表示字符和字符串。举个例子:不要使用和char cResponse; char sUsername[64];
为了支持多语种(如:Unicode),你可以把代码写成更通用的方式:wchar_t cResponse; wchar_t sUsername[64];
#include<TCHAR.H> TCHAR cResponse; TCHAR sUsername[64];
以下项目General设置页面描述用于编译哪个字符集:(通用- >字符集)
![]()
通过这种方式,当你工程被编译成Unicode时,TCHAR就被定义成wchar_t。如果使用ANDI编译,则被翻译成char。你能自由的使用char和wchar_t,工程设置并不会改变其定义。
TCHAR的定义:#ifdef _UNICODE typedef wchar_t TCHAR; #else typedef char TCHAR; #endif
当你设置“ Use Unicode Character Set”时,宏_UNICODE就被定义了,因此TCHAR也就是wchar_t。而当你设置字符集为“ Use Multi-Byte Character Set”,那么TCHAR就是char。同样,为了支持多种字符集和多语言,而使用单一代码库,也要使用特定的函数(宏)。如:使用wcscpy,wcslen,wcscat代替strcpy,strlen,strcat。strlen的定义是:wcslen定义:size_t strlen(const char*);
size_t wcslen(const wchar_t* );
你也许会使用_tcslen,其逻辑定义是:size_t _tcslen(const TCHAR* );
WC是宽字符,因此wcs就是宽字符串。_tcs意味着_T字符串,_T逻辑上是char或者wchar_t。
但是,事实上_tcslen(还有其他_tcs函数)并不是函数,而是宏:#ifdef _UNICODE #define _tcslen wcslen #else #define _tcslen strlen #endif
你也许会疑惑为什么定义成宏而不是函数,原因很简单:库或DLL可以用相同的名称和原型导出一个函数(不包括C++中的重载)。举个例子:当你导出一个函数void _TPrintChar(char);
但是如下情况时:
客户端如何来调用?<span style="font-family: Arial, Helvetica, sans-serif;">void _TPrintChar(wchar_t);</span>
_TPrintChar函数不能神奇的转换成双字节字符,必须有两个函数的各自定义:
同时包括一个简单的宏来隐藏其区别:void PrintCharA(char); // A = ANSI void PrintCharW(wchar_t); // W = Wide character
#ifdef _UNICODE void _TPrintChar(wchar_t); #else void _TPrintChar(char); #endif
此时客户端就能如下调用:
TCHAR cChar; _TPrintChar(cChar);
注意,TCHAR和_TPrintChar将映射到Unicode或ANSI,因此cChar和函数参数也被映射成char或者wchar_t。
宏的确避免了这些复杂性,允许我们操作字符或者字符串时代替使用ANSI或者Unicode函数。很多使用字符串或者字符的Windows函数都利用宏的便利性,对于程序员来说也更方便,因为只要使用一个函数就够了,例如SetWindowText函数:// WinUser.H #ifdef UNICODE #define SetWindowText SetWindowTextW #else #define SetWindowText SetWindowTextA #endif // !UNICODE