推荐用平台API(如Windows的MultiByteToWideChar)或轻量库处理UTF-8与wstring转换;std::wstring_convert已弃用,std::mbstowcs依赖locale易出错,std::from_chars和std::to_wstring不适用于编码转换。

用 std::wstring_convert 转换(C++11–C++17,已弃用但仍有项目在用)
这个方法依赖 std::codecvt_utf8<wchar_t></wchar_t>,常见于旧代码。它能处理 UTF-8 编码的 std::string 到 std::wstring 的转换,但注意:C++17 起被标记为 deprecated,C++20 已移除,新项目别选它。
实际操作时容易卡在 locale 绑定失败或抛出 std::range_error,尤其当输入含非法 UTF-8 字节序列时。建议只用于维护老代码,且必须加 try/catch:
try {
std::wstring_convert<std::codecvt_utf8<wchar_t>> conv;
std::wstring ws = conv.from_bytes("你好");
} catch (const std::range_error&) {
// 输入不是合法 UTF-8
}
用 std::mbstowcs 转换(跨平台,但依赖当前 locale)
它把多字节字符串按当前 C locale 解释后转成宽字符。关键点在于:**结果取决于 setlocale(LC_ALL, "") 是否已调用,以及系统默认 locale 是否支持输入编码**。
常见陷阱:
- 没调用
setlocale就直接用,可能把每个字节当 ASCII 处理,中文全变L'?'或截断 - Windows 控制台默认是 GBK,Linux 终端通常是 UTF-8,同一段代码行为不同
- 输入含空字符会提前终止,
std::string允许嵌入'\0',但mbstowcs把它当结尾
安全用法示例:
setlocale(LC_ALL, "");
std::string s = "你好";
std::vector<wchar_t> buf(s.size() + 1);
size_t len = mbstowcs(buf.data(), s.c_str(), buf.size());
if (len != static_cast<size_t>(-1)) {
std::wstring ws(buf.data(), len);
}
用平台 API 精确控制编码(推荐 Windows + UTF-8 场景)
Windows 上,如果确定输入是 UTF-8(比如从文件、网络或现代 C++ 字符串字面量来),直接用 MultiByteToWideChar 最可靠:
好处是绕过 locale,明确指定 CP_UTF8,不依赖系统设置:
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
立即学习“C++免费学习笔记(深入)”;
int len = MultiByteToWideChar(CP_UTF8, 0, s.c_str(), -1, nullptr, 0);
if (len > 0) {
std::vector<wchar_t> buf(len);
MultiByteToWideChar(CP_UTF8, 0, s.c_str(), -1, buf.data(), len);
std::wstring ws(buf.data());
}
注意:-1 表示包含末尾 '\0',输出也带结束符;若不需要,用 s.length() 并手动补 L'\0'。
为什么不用 std::from_chars 或 std::to_wstring?
std::from_chars 只解析数字,不处理通用字符串编码转换;std::to_wstring 是把数值(如 int、double)转成宽字符串,和 string → wstring 编码转换完全无关——这两个函数名字有误导性,但功能上毫不沾边。
真正跨平台又现代的做法是引入轻量库(如 ICU 或 utf8cpp),或者自己写一个基于 UTF-8 byte pattern 的转换循环。但多数场景下,明确输入编码 + 用对应平台 API,比强求“标准库一行解决”更稳妥。尤其是 Windows 下处理中文路径、文件名时,跳过 locale 直接走 CP_UTF8 几乎是刚需。

















