C++ 中TCHAR, WCHAR, LPSTR, LPWSTR, LPCTSTR 等字符类型总结
C++中常用的字符为1字节或2字节,1个字节的字符又称为ANSI编码,所有的英文字符都可以用ANSI编码实现;2个字节的字符在Windows系统中一般为Unicode编码,是一种可以表示实现所有语言的编码。VC中,默认支持的字符类型为char和wchar_t,分别对应ANSI编码和Unicode编码。
为了使程序适配多语言场景,不建议在代码中使用char或wchar_t,可直接使用TCHAR类型定义字符(串),需要包含对应头文件
1 #ifdef _UNICODE 2 typedef wchar_t TCHAR; 3 #else 4 typedef char TCHAR; 5 #endif
其中,当编译器中“General->Project Defaults->Character Set”选项设置为“Use Unicode Character Set”时,_UNICODE宏则定义,TCHAR表示wchar_t。同理,在涉及到字符串操作的接口时,也推荐使用支持多语言场景的接口_tcscpy、_tcslen、_tcscat,而不是strcpy_s、strlen_s、strcat_s或wcscpy、wcslen、wcscat。头文件
通常,我们使用双引号标识ANSI字符串,比如:"I'm an example. " 这种类型的字符串,每个字符占用一个字节。当我们想要标识UNICODE字符串时,需要添加前缀L,比如:L"I'm an example. " 。这种类型的字符串,每个字符占用两个字节。当然,为了适配多语言场景,也设计了一个通用的字符串前缀,即_T(或TEXT),这个前缀也是宏定义,其在源码中的定义如下[1]:
1 #ifdef _UNICODE 2 #define _T(c) L##c 3 #define TEXT(c) L##c 4 #else 5 #define _T(c) c 6 #define TEXT(c) c 7 #endif
其中,##是粘贴符,当宏_UNICODE已定义时,##可以把_T("Unicode")转换为L"Unicode"。反之,_T("Unicode")仅表示"Unicode"。_T(或TEXT)不能用来实现Unicode和non-Unicode字符之间的转换。
WCHAR是一种Unicode编码类型,其在源码中的定义如下[2]:
1 #if !defined(_NATIVE_WCHAR_T_DEFINED) 2 typedef unsigned short WCHAR; 3 #else 4 typedef wchar_t WCHAR; 5 #endif
其中,只有在编译器的 /Zc:wchar_t选项有效且 /Yu选项无效时,宏_NATIVE_WCHAR_T_DEFINED才会建立[3]。
LPCTSTR是一种指针类型,该类型名可按照如下方式解读[1]:
LP - Pointer, C - Constant, T - TCHAR, STR - String.
根据我们创建工程时的配置,LPCTSTR会映射为LPCSTR(ANSI)或LPCWSTR(Unicode)。
LPSTR是一种指针类型,可能指向的数据编码类型为 ANSI 或 UTF-8,具体由protocol文件决定。LPSTR在源码中的定义如下[4]:
typedef char* PSTR, *LPSTR;
LPWSTR也是一种指针类型,它用32位字符表示16位的Unicode字符,其在源码中的定义如下[5]:
typedef wchar_t* LPWSTR, *PWSTR;
ref:
[1] https://www.codeproject.com/Articles/76252/What-are-TCHAR-WCHAR-LPSTR-LPWSTR-LPCTSTR-etc
[2] https://docs.microsoft.com/en-us/windows/win32/extensible-storage-engine/wchar
[3] https://www.geoffchappell.com/studies/msvc/language/preprocessor/macros/builtin/native_wchar_t_defined.htm
[4] https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/3f6cc0e2-1303-4088-a26b-fb9582f29197
[5] https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/50e9ef83-d6fd-4e22-a34a-2c6b4e3c24f3