在 Windows C++、MFC 或 ATL 项目里,经常会看到两种字符串写法:
L"你好"
_T("你好")
它们看起来都像是在表示中文字符串,但含义并不完全一样。
1. L"你好" 是宽字符字符串
L"你好" 前面的 L 表示这是一个宽字符字符串字面量。
它的类型大致是:
const wchar_t[]
也就是说:
const wchar_t* s = L"你好";
这种写法明确告诉编译器:这个字符串使用 wchar_t 类型保存。
在 Windows 上,wchar_t 通常是 2 字节,常用于 Unicode 版本的 Windows API,例如:
MessageBoxW(nullptr, L"你好", L"提示", MB_OK);
这里的 MessageBoxW 就是宽字符版本的 API。
2. _T("你好") 是一个宏
_T("你好") 不是 C++ 语言本身的语法,而是 Windows / Visual C++ 环境里的一个宏,通常定义在 <tchar.h> 中。
它的作用是根据项目是否启用了 Unicode 编译,自动决定字符串类型。
如果定义了 _UNICODE:
_T("你好")
会被展开成:
L"你好"
如果没有定义 _UNICODE:
_T("你好")
会被展开成:
"你好"
也就是说,_T("你好") 可能是宽字符字符串,也可能是普通窄字符字符串。
3. 二者最大的区别
简单来说:
L"你好"
永远是宽字符字符串。
_T("你好")
取决于编译选项。
可以这样理解:
| 写法 | 含义 | 类型是否固定 |
|---|---|---|
L"你好" |
明确的宽字符字符串 | 固定是 wchar_t |
_T("你好") |
通用文本宏 | 取决于是否定义 _UNICODE |
4. 为什么以前常用 _T?
早期 Windows 程序需要同时兼容两种版本:
一种是 ANSI 版本,也就是普通 char 字符串;
另一种是 Unicode 版本,也就是 wchar_t 字符串。
为了让同一份代码可以在两种模式下编译,微软提供了 TCHAR、_T()、_TEXT() 这一套通用文本机制。
例如:
TCHAR text[] = _T("你好");
如果项目是 Unicode 编译,那么等价于:
wchar_t text[] = L"你好";
如果项目是非 Unicode 编译,那么等价于:
char text[] = "你好";
这样代码就可以在不同字符集设置下切换。
5. 现在应该用哪个?
如果你明确写的是现代 Windows 程序,并且项目使用 Unicode,那么可以直接写:
L"你好"
或者更常见的是配合宽字符 API:
MessageBoxW(nullptr, L"你好", L"标题", MB_OK);
如果你在维护 MFC、ATL 或老的 Windows 项目,并且代码里大量使用 TCHAR、CString、LPCTSTR,那么继续使用 _T() 会更统一:
CString str = _T("你好");
6. 一个常见例子
#ifdef _UNICODE
// Unicode 模式
_T("你好") // 等价于 L"你好"
#else
// 非 Unicode 模式
_T("你好") // 等价于 "你好"
#endif
所以,_T("你好") 的核心作用不是“把字符串变成 Unicode”,而是“根据当前工程设置自动选择字符串类型”。
总结
L"你好" 是 C++ 的宽字符字符串字面量,类型固定是 wchar_t。
_T("你好") 是 Windows 编程中的宏,是否变成宽字符字符串取决于项目是否定义了 _UNICODE。
如果是新项目,通常建议统一使用 Unicode,直接使用宽字符接口或现代字符串类型;如果是 MFC、ATL 或老项目,看到 _T()、TCHAR、LPCTSTR 就要理解它们是为了兼容 Unicode 和非 Unicode 两种编译模式。
