MultiByteToWideChar是Windows下ANSI转WideChar最常用且唯一可靠可控的API;需用CP_ACP传参、两步调用(先查长度再转换)、避免依赖setlocale,输入为GBK等ANSI编码时不可误用CP_UTF8或硬编码936。

ANSI字符串转WideChar最常用的是MultiByteToWideChar
Windows下把ANSI(即系统默认编码,通常是GBK/GB2312)转成wchar_t*,MultiByteToWideChar是唯一可靠、可控的API。别用mbstowcs——它依赖setlocale,而Windows控制台和GUI程序的locale行为不一致,容易在不同机器上出错。
关键点:
-
CodePage参数必须传CP_ACP(ANSI code page),不是CP_UTF8或0 - 输入缓冲区要包含终止符
\0,否则可能截断或越界 - 第一次调用时传
NULL给lpWideCharStr,获取所需wchar_t数量(含结尾\0) - 第二次分配足够空间(
(n+1) * sizeof(wchar_t)),再调用转换
int len = MultiByteToWideChar(CP_ACP, 0, ansi_str, -1, NULL, 0);
if (len == 0) { /* 错误:GetLastError()看原因 */ }
std::vector<wchar_t> wbuf(len);
MultiByteToWideChar(CP_ACP, 0, ansi_str, -1, wbuf.data(), len);
为什么CP_ACP不能换成CP_OEMCP或936
CP_OEMCP对应DOS/OEM控制台编码(如GBK的OEM变体),和GUI程序用的CP_ACP不兼容;硬写936看似能用,但会丢失跨区域可移植性——比如繁体中文系统默认CP_ACP是950,写死936就崩了。
常见错误现象:
立即学习“C++免费学习笔记(深入)”;
- 中文显示为方块或乱码 → 用了
CP_UTF8但输入其实是GBK - 字符串莫名截断 → 第一次调用没传
-1,导致长度计算不含\0 - 偶发崩溃 → 分配空间不足,
MultiByteToWideChar写越界
如果输入其实是UTF-8,该不该用CP_ACP
不该。Windows的“ANSI字符串”语境下,默认指CP_ACP编码,不是UTF-8。如果你确定源数据是UTF-8字节流(比如从网络或文件读来的),必须显式用CP_UTF8,否则会双解码出错。
判断依据很实际:
- 来自
GetWindowTextA、MessageBoxA参数、注册表REG_SZANSI值 → 用CP_ACP - 来自
fopen读取的UTF-8文本、JSON解析结果、curl响应 → 用CP_UTF8 - 不确定来源?先用
IsTextUnicode试探,但更推荐记录源头编码,别猜
宽字符转回ANSI时WideCharToMultiByte要注意什么
反向转换常被忽略兼容性问题:目标ANSI编码可能无法表示某些Unicode字符(比如生僻汉字、emoji)。默认行为是丢弃或替换成?,但你可以控制:
- 传
WC_NO_BEST_FIT_CHARS标志避免“凑合映射”(比如把「?」映成「吉」) - 用
lpDefaultChar和lpUsedDefaultChar捕获替换行为,方便调试 - 返回值为0且
GetLastError()==ERROR_INSUFFICIENT_BUFFER→ 缓冲区不够,不是编码失败
真正麻烦的是:同一个wchar_t*,在简体中文系统转CP_ACP成功,在日文系统可能全变成?——这不是bug,是Windows编码模型的固有限制。


















