C语言与中文的一些测试 (Win, UTF8源码)
C语言如何输出中文?
测试前提:1. 源代码为UTF8编码的文件。2. 中文Windows系统。
测试环境:Windows 10,MinGW-w64 8.1。
如果用Windows SDK,效果可能和我的测试有极大不同,可能可以用UTF8,具体见评论区。
你好
的编码信息
- GBK: C4E3 BAC3
- UTF8: E4BDA0 E5A5BD
- UTF16 LE:4F60 597D
char硬编码字符串
#include <stdio.h>
#include <stdlib.h>
void ShowBytes(char *str)
if (*str == '\0')
printf("EMPTY");
while (*str != '\0')
printf("%hhX ", (unsigned char)*str++);
// 中文的char的最高位为1,如果直接赋值给int或unsigned,会先进行位扩展,再改变类型,结果就是负的
int main()
system("chcp 936");
// system("chcp 65001");
char str[] = "你好";
puts(str);
ShowBytes(str);
}
char硬编码结果
chcp 936:
浣犲ソ
E4 BD A0 E5 A5 BD
chcp 65001:
你好
E4 BD A0 E5 A5 BD
char硬编码结论
- 硬编码的char字符串与文件编码一致,此处是UTF8。
- 输出 字符串时用的编码与chcp一致。
wchar_t硬编码字符串
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <wchar.h>
void ShowBytesWide(wchar_t *str)
if (*str == '\0')
printf("EMPTY");
while (*str != '\0')
wprintf(L"%hX ", (wchar_t)*str++);
int main()
system("chcp 936");
// system("chcp 65001");
setlocale(LC_ALL, "chs");
wchar_t str[] = L"你好";
wprintf(L"%ls\n", str);
// fputws(str, stdout);
ShowBytesWide(str);
}
wchar_t硬编码结果
chcp 936与chcp 65001:
你好
4F60 597D
如果注释掉setlocale,函数不会输出。
如果注释掉wprintf而改用fputws,函数不会输出,原因不明。
wchar_t硬编码结论
- 硬编码的wcahr_t字符串储存的是UTF16的编码。
- 必须使用setlocale,否则无法输出。
- wprintf输出时,会把wchar_t*转换成当前locale的编码,然后输出。
char手动输入输出
int main()
// system("chcp 936");
system("chcp 65001");
char str[10];
gets(str);
// scanf("%s", str);
puts(str);
ShowBytes(str);
}
char手动结果
chcp 936:
你好
C4 E3 BA C3
chcp 65001:
你好
EMPTY
char手动结论
- chcp 936时能成功读入,且编码为GBK。
- chcp 65001时gets和scanf无法成功读入!
wchar_t手动输入输出
int main()
system("chcp 936");
// system("chcp 65001");
setlocale(LC_ALL, "chs");
wchar_t str[10];
wscanf(L"%ls", str);
wprintf(L"%ls\n", str);
ShowBytesWide(str);
}
wchar_t手动结果
chcp 936:
你好
4F60 597D
chcp 65001:
你好
EMPTY
wchar_t手动结论
- chcp 936时能成功读入,且编码为UTF16。
- chcp 65001时wscanf无法成功读入!
最终结论
-
说好的UTF8呢?怎么全都是GBK和UTF16?
理论上char+chcp 65001就是UTF8,然而读取失败。没有办法手动输入UTF8编码的字符串,只有编译时已经存在的能用。 -
应该如何处理中文?
chcp 936 + wchar_t。因为这是唯一成功的方案。
附加测试:wprintf的%ls
根据
cppreference
,%s对应的是
char*
,%ls对应的才是
wchar_t*
。
#include <locale.h>
#include <stdio.h>
#include <wchar.h>
int main()
#ifdef linux
setlocale(LC_ALL, "zh_CN.UTF-8");
#else
setlocale(LC_ALL, "chs");
#endif
char *strc = "c你好";
wchar_t *strw = L"w你好";
wprintf(L"%s\n", strc);
wprintf(L"%s\n", strw);
wprintf(L"%ls\n", strc);
wprintf(L"%ls\n", strw);
}
Windows下的测试结果:
w你好