必须明确编码,禁用reinterpret_cast;Windows首选MultiByteToWideChar(CP_UTF8),跨平台推荐utf8cpp或ICU,std::codecvt等已弃用。

std::string 到 std::wstring 转换必须明确编码,不能直接 reinterpret_cast
直接用 reinterpret_cast 或构造函数 std::wstring(str.begin(), str.end()) 是错的——这只会把每个 char 当作低字节复制,遇到 UTF-8 多字节序列(如中文、emoji)必然乱码。关键前提是:你得知道 std::string 里存的是什么编码。绝大多数现代场景下它是 UTF-8,不是本地 ANSI(如 Windows-1252 或 GBK),这点极易被忽略。
Windows 上用 MultiByteToWideChar(UTF-8 → UTF-16)最可靠
Windows API 的 MultiByteToWideChar 明确支持 CP_UTF8,是处理 UTF-8 字符串转 std::wstring(即 UTF-16)的首选。它能正确解析变长 UTF-8 序列,并报告转换错误。
- 调用前先用
MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, nullptr, 0)获取目标长度(含终止 null) - 分配
std::vector<wchar_t></wchar_t>缓冲区,再调用第二次完成转换 - 务必检查返回值是否为 0,若为 0 可用
GetLastError()判断是否因非法 UTF-8 字节导致失败 - 不要硬写
CP_ACP—— 它依赖系统区域设置,跨机器行为不一致
std::wstring string_to_wstring(const std::string& str) {
if (str.empty()) return {};
int len = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, nullptr, 0);
if (len == 0) throw std::runtime_error("Invalid UTF-8 sequence");
std::vector<wchar_t> buf(len);
MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, buf.data(), len);
return std::wstring(buf.data());
}
跨平台方案:用 std::codecvt_utf8_utf16(已弃用,但仍有项目在用)
std::codecvt_utf8_utf16 在 C++17 被标记为 deprecated,C++20 彻底移除,但它仍在不少旧代码库中出现。如果你必须维护这类代码,要注意:
- 它只能用于窄字符串是 UTF-8 的前提下;若输入含非法序列,
out迭代器可能未完全写入且不报错 - 必须配合
std::wbuffer_convert和std::mbstate_t使用,状态对象不能复用多次转换(否则残留状态导致后续失败) - Clang 和较新 GCC 默认禁用 deprecated 警告,但编译会失败;需加
-D_GLIBCXX_USE_CXX11_ABI=0或改用 libstdc++ 兼容模式
现代 C++ 推荐:用 ICU 或 utf8cpp 等轻量库
标准库不再提供安全的文本编码转换能力,硬啃 std::codecvt 得不偿失。更实际的选择是引入小而专注的第三方库:
立即学习“C++免费学习笔记(深入)”;
-
utf8cpp(头文件-only):用utf8::utf8to16直接转到std::vector<uint16_t></uint16_t>,再构造std::wstring;对无效序列抛utf8::invalid_utf8异常 - ICU 的
ucnv_convert:功能最全,支持所有编码,但二进制体积大,适合大型应用 - 避免自己手写 UTF-8 解码循环——边界条件(如过长序列、代理对、空终止)极难覆盖完整
真正容易被忽略的点是:转换不是单向“解码”就完事。如果你后续要把 std::wstring 写回文件或发给 Win32 API,要确认接收方是否真按 UTF-16 解释;比如写文本文件时,没写 BOM 的 UTF-16 文件在某些编辑器里会被误判为 ANSI。



















