彻底搞清C++中各种字符编码:Unicode,UTF-8,ANSI之间的相互转换和正确打印!

原来我编程主要用C#,C#中字符串的编码就只有一种:16位的Unicode。如果你把文本文件读到字符串中,得到的文本编码就是Unicode,也就是小端的UTF 16。而现在文本文件的编码都是UTF 8的。这就意味着C#在把文本文件读入字符串时,是自动进行了UTF-8转码Unicode 的。C#控制台程序在把字符串输出到终端上时,大概又自动进行了从Unicode到A N S I编码的转换,因为控制台默认的页面编码是936,也就是简体中文,用的编码是GB2132。

字符类型

赋值前缀

对应字串

打印方法

编码

‘一’码值

char

= '一'

string

cout

MSC:ANSI Clang:utf-8

d2 bb(ANSI GB2132)

默认字串编码随编译器

char8_t

= u8'一'

UTF-8

e4 b8 80

wchar_t

= L'一'

wstring

wcout

UTF-16LE(小端)

4e00

windows宽字串,中文不能正确打印

char16_t

= u'一'

u16string

UTF-16(大或小端)

4e00

windows下和wchar_t没区别

char32_t

= U'一'

u32string

UTF-32(大或小端)

4e00

大或小端视系统而定

换句话说就是,C#自动把字串格式转换的事情都做了。我们在程序中处理字串时,只需要处理Unicode就行了。而到了C++这问题就复杂了。C++里用来存储字符的char类型就有好几个,用的编码也有好几种,C++也不会帮你做自动转码。所以就逼着我研究了半天,把这些字符类型,以及它们之间的相互转换搞清楚了,结果就在上面这个表中。

我们管引号前面没加任何前缀修饰的字串叫默认字串,C++中这个默认字串的编码是由编译器决定的,微软的编译器默认用的是ANSI编码,因为我们中文系统中的控制台默认页面编码是936,简体中文,用的就是ANSI中的GBK国标码。Clang编译器用的是UTF-8编码,所以如果不用chcp命令把控制台的页面编码改为95001,也就是UTF-8。Clang编译的控制台程序如果输出了中文就会显示乱码。

C++ 控制台程序中输出UTF8字符乱码问题解决方法

这篇文章说了如何在程序中设定控制台的页面编码,以免出现乱码。总之,能在控制台中正确显示的编码只有两种,要么是UTF-8,要么是ANSI。wstring虽然也可以输出,但由于它的编码是Unicode,所以如果里面有中文,那它是无法正确显示的。如果我们用16位的Unicode处理完字串想打印输出,那就必须对它进行转码,要么转UTF-8,要么转ANSI。那这又该如何转呢?

彻底搞清C++中各种字符编码:Unicode,UTF-8,ANSI之间的相互转换和正确打印!_第1张图片

Windows有提供两个转换函数可以进行互转,就是上图那两个划了红线的函数。用它们还有点小复杂,要先调用一下获取输出字串的长度,然后根据这个长度新建一个字串来接收输出,然后再掉用一次进行真正的转换。上面的代码是我从Stack overflow上抄来的,亲测可用,代码在下面这个库中:

becomequantum (becomequantum) · GitHub

Cpp性能测试.cpp

另外我还在Github上发现了一个叫simdutf的库,提供了UTF-8到UTF-16的互转函数,并用SIMD指令加速了转码过程。我也弄来测试了下一,代码如上图所示。我还测试一下它的转换速度,比windows自带的函数大概快了2.5倍,用这个库是跨平台的,windows自带的函数只能在windows下用。

你可能感兴趣的:(c++,java,开发语言)