生而自由

自由而无用的灵魂

VC中的字符编码

先理一下基本的概念,在VC中字符编码有ANSI(也称为多字节字符集)和UNICODE(宽字节字符集)两种。ANSI是指本地编码,在中文环境下就是指GBK编码,而UNICODE编码、在VC中使用的是UTF-16。

同时,说到“编码”,一个是指源码字符集(the source character set),这个好理解,就是指cpp hpp h等源代码文件的编码;另一个是指执行字符集(the execution character set),例如“const char *str="中文"”,这个str指向的内存中的字符编码就是执行字符集了。 注意在本文中,“编码”和“字符集”我会混用,反正指代的含义是同一个。

那么先总结第一点:在VC中处理源文件时,只有UTF-16(BE,LE均可,有无BOM均可)、UTF-8(带BOM)的源文件会被编译器自动识别文件编码, 其它格式的文件(包括不带BOM的UTF-8)统统视为ANSI编码处理

所以如果在无BOM的UTF-8源文件中写中文字符串,VC会把UTF-8字符串当作GBK字符串来处理,这时一般会产生一个warning:“warning C4819: 该文件包含不能在当前代码页(936)中表示的字符”。后果就是字符串面目全非,大概就是“手持两把锟斤拷”了吧......

 

以为这样就完了?用带BOM的UTF-8源文件就行了? 远远没有!  第二点来了:为了兼容老版本的VC,在没有声明执行字符集(具体怎样声明见下文第三点)的情况下,即使源文件是UTF-16、UTF-8(带BOM),VC会将字符常量从源文件的编码转换为ANSI编码,同时使用ANSI作为执行字符集

假设你已经使用了UTF-8(带BOM)编码的源文件,那么实际情况如下:

 

 

所以有了第三点:对于UTF-8(带BOM)的源文件,在声明使用UTF-8编码的情况下,VC才会使用UTF-8作为执行字符集。这才是我们想要的。

 

最后一点来了:对于 “_T()”、“L” 这两个宏(这里只讨论在UNICODE下的情况),无论源文件编码、无论是否声明execution_character_set,它们都会安全地声明UNICODE(即UTF-16)编码的字符串常量(注意是wchar_t类型)

 

可以发现UTF-8在表示一个字符时有可能占用1到3个字节,在表示中文时是占用3个字节的,而UTF-16始终是使用2个字节来表示。 因此在存储中文的情况下,UTF-16占用的内存是更小的。但是可以发现UTF-8是完全“兼容”ASCII的(即对于只使用ASCII字符的UTF-8字符串、每个字节都是一个ASCII字符。另外GBK也是兼容ASCII的),而UTF-16由于固定使用2个字节因此可以说是不兼容ASCII的。

 

最后再提一下Qt吧(本文中指Qt5),Qt中的字符串也使用UTF-16编码存储,所以每个QChar占2个字节。 同时Qt5默认执行字符集是UTF-8,也就是Qt认为字符串常量的编码是UTF-8的。所以当写下代码:QString str = "中文"  时,赋值操作符实际上调用了QString的 fromUtf8() 方法,将UTF-8编码的字符串常量转换为QString内部的UTF-16编码。

点赞

发表评论

电子邮件地址不会被公开。 必填项已用*标注

This site uses Akismet to reduce spam. Learn how your comment data is processed.