windows用multibytetowidechar/widechartomultibyte(codepage=936/cp_utf8),linux/macos用iconv(编码名严格匹配),std::codecvt和std::wstring_convert已弃用,应避免使用。

Windows平台用MultiByteToWideChar和WideCharToMultiByte做GBK/UTF-8互转
Windows API 提供的这两个函数是本地化编码转换最稳妥的选择,绕过C++标准库的模糊抽象,直接对接系统代码页。关键不是“能不能转”,而是选对CodePage参数:CP_UTF8对应UTF-8,936对应GBK(简体中文),CP_ACP则读取当前系统ANSI代码页(通常是GBK)。
常见错误是传错缓冲区长度:输入字符串长度按字节计,但WideCharToMultiByte的cchWideChar参数要传宽字符数(即wstr.length()),而MultiByteToWideChar的cbMultiByte要传多字节字符串字节数(不是strlen,得用mbstowcs(nullptr, str.c_str(), 0)预估或直接传-1含结尾\0)。另外,目标缓冲区必须预留足够空间,UTF-8转宽字符时单个汉字最多占3字节→2宽字符,GBK转UTF-8时单个汉字2字节→3字节,别硬算固定倍数。
示例:GBK字符串转UTF-8
std::string gbk_to_utf8(const std::string& gbk) {
int wlen = MultiByteToWideChar(936, 0, gbk.c_str(), -1, nullptr, 0);
std::vector<wchar_t> wbuf(wlen);
MultiByteToWideChar(936, 0, gbk.c_str(), -1, wbuf.data(), wlen);
int ulen = WideCharToMultiByte(CP_UTF8, 0, wbuf.data(), -1, nullptr, 0, nullptr, nullptr);
std::vector<char> ubuf(ulen);
WideCharToMultiByte(CP_UTF8, 0, wbuf.data(), -1, ubuf.data(), ulen, nullptr, nullptr);
return std::string(ubuf.data());
}</char></wchar_t>
Linux/macOS用iconv处理UTF-8/GB18030/ISO-8859-1等任意编码
iconv是POSIX标准接口,支持系统已安装的所有编码(iconv -l可查),比Windows API更通用,但需手动管理句柄和内存。核心陷阱在于:源/目标编码名必须严格匹配iconv -l输出(如"GB18030"不能写成"GBK","UTF-8"末尾不能带横杠),且iconv()会修改输入指针,循环调用前必须重置。
实际使用中,iconv_open()失败常因编码名拼错或系统未装对应glibc locale包;iconv()返回(size_t)-1不一定是错误——也可能是输出缓冲区满,此时需检查errno == E2BIG并扩容再试。别忽略iconv_close(),否则句柄泄漏。
要点:
- 用
iconv_t cd = iconv_open("UTF-8", "GB18030")初始化,注意参数顺序是to, from - 输入缓冲区指针
&inptr和长度&inbytesleft必须传地址,函数内部会更新它们 - 输出缓冲区每次填满后,把已转换部分移出缓冲区头,避免重复转换
- 转换完成后调用
iconv(cd, nullptr, nullptr, &outptr, &outbytesleft)冲刷残留状态(如UTF-8 BOM)
跨平台项目慎用std::codecvt,C++17已弃用
别被旧教程误导:std::codecvt_utf8等模板在GCC 7+、Clang 5+中默认禁用,MSVC虽保留但行为不一致(如对非法UTF-8序列处理方式不同)。它要求facet绑定到std::locale,而locale构造本身可能抛异常,且无法指定错误处理策略(遇到乱码直接std::runtime_error)。真实项目里,这玩意儿上线就踩坑。
替代方案只有两个:Windows走API,其他平台走iconv;或者引入轻量库如utf8cpp(仅头文件,专注UTF-8与UTF-16互转)或icu4c(功能全但体积大)。如果只是处理用户输入的文件名或HTTP header,优先用系统原生接口——它们经过数十年打磨,比标准库模拟层可靠得多。
UTF-8和UTF-16互转时,std::wstring_convert已彻底移除
C++11引入的std::wstring_convert在C++17被标记为废弃,C++20直接删除。现在连MSVC最新版编译都会报错。试图用它转UTF-8/UTF-16,结果只能是编译失败或链接时报undefined reference。
正确做法分场景:
- Windows下:继续用
MultiByteToWideChar(CP_UTF8, ...)和WideCharToMultiByte(CP_UTF8, ...) - Linux/macOS:用
iconv,编码名填"UTF-8"和"UTF-16LE"(注意字节序,Windows默认LE,Linux常用BE需显式写"UTF-16BE") - 纯内存操作且确定无BOM:手写简单循环,UTF-8解码靠查首字节高比特位判断字节数,UTF-16编码按代理对拆分,但务必校验非法码点(如0xD800–0xDFFF单独出现)
真正麻烦的是混合环境——比如Windows程序读取Linux生成的UTF-8文件,又得写回GBK。这时必须明确每个环节的编码契约,不能依赖“自动检测”。文件开头的BOM只对UTF-16/UTF-32有效,UTF-8的BOM(EF BB BF)是可选且常被忽略的,别把它当银弹。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











