为何Windows控制台中setlocale会导致fputs输出乱码?
Windows控制台程序中stdout与LC_CTYPE、SetConsoleOutputCP的行为差异问题
我的Windows系统ANSI代码页为GBK,开发控制台程序时发现以下特殊行为:
测试代码1(fputs操作stdout与文件)
// SetConsoleOutputCP(65001); // 代码页936或65001均不影响结果 char utf8[] = { 0xE4, 0xB8, 0xAD, 0xE5, 0x9B, 0xBD, '+', '\n', '\0'}; // “中国+”的UTF-8字节序列 char gbk[] = { 0xD6, 0xD0, 0xB9, 0xFA, '-', '\n', '\0' }; // “中国-”的GBK(936)字节序列 char* currentLocale = setlocale(LC_CTYPE, "zh_CN.UTF-8"); // "zh_CN.UTF-8" FILE* file = fopen("G:/1.txt", "wb"); fputs(utf8, stdout); // 输出“中国+” fputs(gbk, stdout); // 无输出 fputs(utf8, file); fputs(gbk, file); currentLocale = setlocale(LC_CTYPE, "chs.936"); // "Chinese_China.936" fputs(utf8, stdout); // 输出“涓浗+” fputs(gbk, stdout); // 输出“中国-” fputs(utf8, file); fputs(gbk, file);
使用命令将标准输出重定向至文件:
charset.exe > G:/stdout.txt
对比重定向的stdout.txt与代码中直接写入的file.txt的十六进制内容:
| first fputs | second fputs | third fputs | fourth fputs | |
|---|---|---|---|---|
| stdout.txt | E4 B8 AD E5 9B BD 2B 0D 0A | D6 D0 B9 FA 2D 0D 0A | E4 B8 AD E5 9B BD 2B 0D 0A | D6 D0 B9 FA 2D 0D 0A |
| file.txt | E4 B8 AD E5 9B BD 2B 0A | D6 D0 B9 FA 2D 0A | E4 B8 AD E5 9B BD 2B 0A | D6 D0 B9 FA 2D 0A |
可见:当stdout重定向到文件时,修改LC_CTYPE前后,fputs(str, stdout)输出的字节序列完全一致;但直接输出到控制台时,stdout的显示结果随LC_CTYPE的改变而变化。
最初怀疑这与SetConsoleOutputCP有关,但测试发现无论设置代码页为936还是65001,都不影响上述代码的控制台输出结果。
测试代码2(WriteFile操作STD_OUTPUT_HANDLE)
SetConsoleOutputCP(65001); // 设为936时GBK输出正常,设为65001时UTF-8输出正常 HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); DWORD dwBytesWritten; char* currentLocale = setlocale(LC_CTYPE, "zh_CN.UTF-8"); // "zh_CN.UTF-8" WriteFile(hStdout, utf8, sizeof(utf8), &dwBytesWritten, NULL); // 输出“中国+” WriteFile(hStdout, gbk, sizeof(gbk), &dwBytesWritten, NULL); // 输出“�й�-” currentLocale = setlocale(LC_CTYPE, "chs.936"); // "Chinese_China.936" WriteFile(hStdout, utf8, sizeof(utf8), &dwBytesWritten, NULL); // 输出“中国+” WriteFile(hStdout, gbk, sizeof(gbk), &dwBytesWritten, NULL); // 输出“�й�-”
测试结果:WriteFile仅受SetConsoleOutputCP影响,不受LC_CTYPE改变的影响。
核心疑问
STD_OUTPUT_HANDLE与stdout均指向控制台,理论上相同字节序列的显示应该一致,但实际结果完全不同:
- 为什么输出到控制台时,stdout的表现会随LC_CTYPE改变,而重定向到文件时字节序列无变化?
- 为什么
SetConsoleOutputCP不影响stdout的控制台输出,却能影响WriteFile的输出?
内容的提问来源于stack exchange,提问作者ok im
相关产品推荐
相关产品推荐

