C++中的中文编码 乱码的根源及解决方案

总结

ASCII规定了127个字符编码,而一个字节最多能表示256种。所以可以根据第一位来判断是不是ASCII编码,如果不是说明这是一个多字节编码。

char 与 std::string,英文字符在 UTF-8 中使用一个字节存储,中文字符使用三个字节存储。

C++ 11 开始支持 UTF-8、UTF-16 和 UTF-32 字符串常量的声明,分别使用 u8""、u"" 和 U"" 作为声明的标志。

wchar_t 与 std::wstring解决多字符编码,占两个字节,且需要使用适配的 std::wcout 和 std::wofstream。windows中的编译器一般将wchar_t定为2个字节宽,而linux中的编译器一般定义wchar_t为4字节宽。用常量字符给wchar_t变量赋值时,前面要加L。如: wchar_t wch2 = L’中’;用常量字符串给wchar_t数组赋值时,前面要加L。如: wchar_t wstr2[3] = L”中国”。

编码场景:

  • 源码字符集(the source character set):源代码文件是使用何种编码字符集保存的
  • 执行字符集(the execution character set):源代码经过编译、链接后的可执行文件是使用何种编码字符集保存的,程序实际执行时,内存中的字符串编码就是执行字符集
  • 运行环境编码:操作系统(或者当前控制台环境)用于显示文字的编码字符集

乱码的根源:源代码文件(源码字符集)经过编译/链接,生成可执行文件(执行字符集),最后程序运行于实际环境中(运行环境编码)。在这过程中如果有字符集不匹配,最终就无法显示预期的文字信息,甚至产生乱码。

  • 编译器在编译源代码时,会将源码字符集转化为执行字符集,如果编译器不能正确识别源码字符集,就得不到正确的字符串数据。
  • 可执行文件在实际运行环境中执行时,为了在控制台(或者其他UI)上显示出字符串,就要将执行字符集转化为运行环境的字符集。如果运行环境的字符集与执行字符集不同,也会导致乱码。

总结起来,要想使程序不会乱码,必须满足:

  • 编译器准确识别了源码字符集,从而得到正确的字符串数据(执行字符集)。

  • 运行环境的编码与执行字符集相同。

代码相关

一般在程序中为了支持国际化,在程序初始化时,将 locale 设置为系统配置的 Native ANSI 字符集,即执行:setlocale(LC_ALL, “”)。

可以查看文件编码格式:

:file main.cc
main.cc: C++ source text, UTF-8 Unicode text

GCC的源码字符集与执行字符集默认都是UTF-8编码,也就是说默认情况下GCC都是按UTF-8来解析源码,编译后的执行字符集也是UTF-8。当然GCC也提供改变默认情况的编译选项:

-finput-charset=charset 用于指定源码字符集
-fexec-charset=charset 用于指定执行字符集

还有一个参数是:

-fwide-exec-charset=charset

默认情况下,gcc在Windows平台下,宽字符串串常量的每个字符是16位UTF-16类型,在Linux平台下,宽字符串串常量的每个字符是32位UTF-32类型,使用-fwide-exec-charset=charset这个参数,可以改变宽字符串串常量的类型。例如在x86的机器环境,Linux操作系统下,要使例如 L"汉字" 编译后保存为UTF-16的字符串,则可以使用 -fwide-exec-charset=UTF-16LE。

控制台查看编码:

:locale
LANG="zh_CN.UTF-8"
LC_COLLATE="zh_CN.UTF-8"
LC_CTYPE="zh_CN.UTF-8"
LC_MESSAGES="zh_CN.UTF-8"
LC_MONETARY="zh_CN.UTF-8"
LC_NUMERIC="zh_CN.UTF-8"
LC_TIME="zh_CN.UTF-8"
LC_ALL=
参考

https://sf-zhou.github.io/programming/chinese_encoding.html

https://www.iteye.com/blog/jimmee-2165685

https://blog.csdn.net/benkaoya/article/details/59522148

你可能感兴趣的:(C++中的中文编码 乱码的根源及解决方案)