说说字符编码的那些事儿
ASCII编码,就是英文显示文字所需要的256个字符(比如,英文字母、数字、标点符号等等),每个字符用一个字节表示,即单字节编码(SBCS,char),ASCII码表定义了数值和字符的映射关系。
ANSI在保留ASCII编码的基础上,对其进行了扩展,使用2个(或多个)字节来代表一个字符,即多字节编码(MBCS,char),它是一种泛称,要结合具体的CodePage(也称编码字符集、代码页)才能确定编码。不同国家或地区制定了不同的标准(数值与字符的映射关系),通过不同的CodePage来定义各自不同的映射关系。不同语言的操作系统,使用的CodePage不一样,比如中文操作系统ANSI代表GB2312,日文操作系统ANSI代表JIS。GBK、GB2312是定义汉字编码的2个CodePage,其中GB2312是对GBK的扩展,完整包含GBK字符集。
UNICODE对全世界所有语言文字进行统一编码,它有2种规范UCS-2、UCS-4,一般使用UCS-2,它规定字符一律用两个字节表示,即双字节编码(DBCS,wchar)。UTF8、UTF16是UNICODE编码存储、传输方式的2种不同实现。UTF8用一个字节表达英文字母,用两个(或多个)字节表达其他语言中的字符,UTF16统一用两个字节表达一个字符(包括英文字母、其他文字),编码与UNICODE是等价的。BOM(byte order mark),即文本文件最开头的几个标识字节,用来说明编码方式,utf-8的BOM是0xef 0xbb 0xbf,utf-16le(Little Endian)的BOM是0xff 0xfe,utf16-be(Big Endian)的BOM是0xfe 0xff。
UTF8、UTF16实际上与ANSI是同一层次上的概念,他们都是一种字符编码方式,区别在于,UTF8、UTF16使用的是UNICODE定义的一个能容纳全世界所有语言的CodePage,即UTF8、UTF16代表的是一种确定的字符编码,而ANSI则需结合具体的CodePage才能确定编码方法,所以我们在切换文件编码格式时,经常看到UTF8通常和GB2312、ISO-8859-1等CodePage以平级的形式出现。UNICODE、ASCII都可以看做是一个CodePage,定义了数值和字符的映射关系,其中ASCII码表被所有编码方式兼容,这意味着英文内容,不论以那种编码方式处理,总能被正确显示。
CodePage不仅要定义数值和本地文字的映射关系,还要定义数值和UNICODE字符的映射关系,这样,不同的ANSI编码(CodePage),就可以通过UNICODE互相转换了。不过,这种字符编码转化,通常只有在UTF8(或其他UNICODE编码实现)与本地CodePage间进行才是有意义的,在本地CodePage与其他语言的CodePage间转化没有任何意义,文字显示和语义都是错误的。CodePage可以用数值型ID表示,也可以用字符串型name表示,注意ID和name并非是业界统一定义的,比如gb2312字符集,在VS中的名称为gb2312,而iconv中对应的名称则是cp936。
Windows平台的API有2套,分别是unicode版和ansi版,若使用unicode版的API,要确保传入的字符串是unicode编码,若使用ansi版的API,要确保传入的字符串编码与操作系统的默认字符集编码匹配,比如简体中文操作系统下,传入的字符串必须是gb2312编码(utf8编码不行),否则中文字符就会显示为乱码,这就是一切乱码的根本原因。当你用文本编辑器打开一个文本文件时,编辑器会根据文件自身提供的信息,推测文件编码方式,然后将其转换成操作系统的默认字符集进行显示,如果编辑器推测错误则可能产生乱码,此时,你可以手工指定按哪种编码方式对文本内容进行转换。
Visual Studio默认按ANSI编码保存和处理源文件,因此在VS中打开一个UTF8编码的源文件,中文会显示成乱码,可以通过修改VS默认编码解决此问题。要注意的是,即使把VS默认编码改成UTF8,代码中定义的字符串常量在程序执行时,仍然是按操作系统的默认字符集编码,而非源文件保存时使用的编码。比如代码中定义了一个字符串常量"中国",即使源文件是以UTF8编码保存,但在代码执行时,"中国"这个常量依然使用的是操作系统的默认字符集编码,可以通过将字符串常量输出到日志文件证实。其实这点也不难理解,程序实际运行时使用的字符串常量,来自于PE文件,而非源文件,编译器完全可以在编译阶段,将常量字符串编码进行转换(从源文件编码,转化为操作系统默认编码),然后输出到obj文件中,最终链接到PE文件里。
最后再补充一点,WINDOWS简体中文操作系统默认使用gb2312字符集,linux(含android、mac、ios等)操作系统默认使用的都是utf8编码,这意味着linux对不同地区的语言文字有着更为广泛的支持!
- 顶
- 1
- 踩