Windows下需调用SetConsoleOutputCP(65001)设置控制台输出为UTF-8,且必须在cout首次使用前调用;Linux/macOS依赖终端locale支持UTF-8,无需额外API;跨平台应使用_WIN32条件编译隔离逻辑。

Windows下用SetConsoleOutputCP设置控制台输出编码
Windows控制台默认用GBK或GB2312,直接cout 会乱码。必须显式调用<code>SetConsoleOutputCP把输出代码页设为UTF-8(即65001)。
注意:这个API只影响输出,输入仍需额外处理;且必须在cout或wcout首次使用前调用,否则无效。
-
SetConsoleOutputCP(65001)是必需步骤,不调用就不可能正常显示UTF-8字符串 - 如果程序里混用
printf和cout,优先用SetConsoleOutputCP而非setlocale,后者对cout效果不稳定 - 返回值为非零表示成功,建议检查:
if (!SetConsoleOutputCP(65001)) { /* 错误处理 */ }
Linux/macOS不需要设置,但要注意终端本身是否支持UTF-8
POSIX系统控制台原生支持UTF-8,std::cout输出UTF-8字节流即可正常显示——前提是终端环境变量LANG或LC_ALL已设为含utf8的值(如en_US.UTF-8)。
常见问题不是C++代码出错,而是终端没生效:
立即学习“C++免费学习笔记(深入)”;
- 运行
locale确认输出中LANG=.*UTF-8存在;若没有,临时用export LANG=en_US.UTF-8修复 - 某些SSH客户端(如旧版PuTTY)默认禁用UTF-8,需在连接配置里勾选“UTF-8”编码
- VS Code内置终端有时缓存旧locale,重启终端或整个VS Code更可靠
跨平台写法:避免硬编码,用__cplusplus和_WIN32条件编译
同一份代码在Windows和Linux上都要跑,就不能只写SetConsoleOutputCP。得用预处理器隔离平台逻辑。
示例片段:
#ifdef _WIN32
#include <windows.h>
#endif
<p>int main() {</p><h1>ifdef _WIN32</h1><pre class="brush:php;toolbar:false;">if (!SetConsoleOutputCP(65001)) {
return 1;
}endif
std::cout << "你好,世界" << std::endl;
}
- 别用
#ifdef __linux__,因为macOS也会进这个分支;统一用_WIN32判Windows更稳妥 - 头文件
<windows.h></windows.h>只在Windows下包含,否则编译失败 - 不要试图在Linux下调用
SetConsoleOutputCP——它根本不存在,链接会报undefined reference
宽字符wcout不是替代方案,反而更容易出错
有人想绕过代码页,改用std::wcout加setlocale(LC_ALL, "")。这在Windows上几乎必然失败:
-
wcout在Windows控制台默认绑定到UCS-2,不是UTF-16,且与代码页强耦合 -
setlocale(LC_ALL, "")在MinGW或MSVC不同版本行为不一致,经常导致wcout完全不输出 - 即使成功,
L"中文"字面量在UTF-8源文件里会被编译器按当前代码页解释,可能生成错误宽字符 - 结论:坚持用
std::cout+ UTF-8字节流 +SetConsoleOutputCP(65001)最稳
真正麻烦的是混合场景:比如程序既输出日志到控制台,又写入UTF-8文件。这时候控制台代码页设置不影响文件写入,但别忘了fopen在Windows下开"wt"模式时默认用系统代码页——要写UTF-8文件得用"wb"或std::ofstream配合imbue。这点容易忽略。


















