Unity3D热门教程

游戏开发工具

C语言到底使用什么编码?谁说C语言使用ASCII码,真是荒谬!

C编译器实际上本身并不识别和处理UTF-8、GBK等编码,它只认ASCII字符,通过ASCII字符解析代码,至于多字节字符,比如注释、字符串中的中文字符,C编译器根本不管,它只当字节序列看待,反正ASCII字符已经能正确定界了。因此,实际上字符串中的中文字符,就是按照源代码中的字节序列直接存储的。

真正识别字符编码的地方是终端,终端收到标准输出流中的字节序列,然后按设定的字符编码方式(如UTF-8、GBK)解析这些字节序列,解析成一个个字符(此时就是真正的字符了,比如中文字符),然后绘制到界面中。

因此,要使得中文正常显示,就要保证源文件用的字符编码和终端显示用的字符编码是一样的

类Unix操作系统现在已经基本将各方面的字符编码都统一成了UTF-8,所以基本不会出问题。问题主要在Windows上。

Windows上,终端(cmd和Powershell)的默认编码是GBK(代码页936),因此,一般将源文件编码方式设置为GBK,则中文字符就能在终端中正常显示。但是,GBK毕竟不是全球通行的字符编码,最好还是用UTF-8,那么就必须将终端的编码方式设置为UTF-8。如果是交互式终端,可以通过执行chcp 65001来,然后./程序.exe就能看到UTF-8源文件编译来的程序中文正常了。交互式使用终端时,还可以用Git for Windows自带的终端,是默认UTF-8编码的,但是不支持交互式输入。

但是,如果是直接双击执行程序,Windows会使用cmd来显示控制台程序的输出,此时默认代码页是936,字符编码为GBK,那么UTF-8源文件编译来的程序就会乱码。此时可以通过在源代码中加入system("chcp 65001");(需要stdlib.h),来通过程序改变代码页。

Visual Studio中,源代码文件的编码格式是UTF-8 with BOM,之所以加BOM是VS为了确定地识别UTF-8。编译时,VS通BOM检测到源文件的编码是UTF-8,会先将源代码转成本地的字符编码GBK(原来的文件不变),然后编译得到GBK的程序。如果把源文件的编码改成UTF-8 without BOM,就不会做这样的转换。同理,UTF-16 LE、UTF-16 BE都有这样的转换机制。

一、编码

编码是用预先规定的方法将文字、数字或其它对象编成数码。为保证编码的正确性,编码要规范化、标准化,即需有标准的编码格式。


我们都知道文本在计算机中是以二进制来进行存储,这就需要把文字通过一定的规则转换成二进制来存储。这种规则就是编码。

每个不同的国家,不同的地区都有自己不同的语言文字,这些文字通过不同的编码,转换成二进制信息进行存储。使用什么编码格式编码,就需要使用相同的格式解码。

为了便于文件全球化交换与使用,有一些编码规则支持了很多语言的转换规则。通过这种编码规则,就可以支持多种语言。

常见的编码格式有ASCII、ANSI、GBK、GB2312、UTF-8、GB2312-80和Unicode等。


二、C语言的编码

C语言是 70 年代的产物,那个时候只有ASCII,各个国家的字符编码都还未成熟,所以C语言不可能从底层支持 GB2312、GBK、Big5、Shift-JIS等国家编码,也不可能支持 Unicode 字符集。


在C语言中字符有两种,一种是窄字符,另一种是宽字符。


只有 char 类型的窄字符才使用 ASCII 编码

char 类型的窄字符串、宽字符和宽字符串都不使用 ASCII 编码!

可以肯定的说,在现代计算机中,窄字符串已经不再使用 ASCII 编码了,因为 ASCII 编码只能显示字母、数字等英文字符,对汉语、日语、韩语等其它地区的字符无能为力。对于窄字符串,C语言并没有规定使用哪一种特定的编码,只要选用的编码能够适应当前的环境即可,所以,窄字符串的编码与操作系统和编译器有关。


三、程序的编码

源文件使用什么编码

源文件用来保存我们编写的代码,它最终会被存储到本地硬盘,或者远程服务器,这个时候就要尽量压缩文件体积,以节省硬盘空间或者网络流量,而代码中大部分的字符都是 ASCII 编码中的字符,用一个字节足以容纳,所以 UTF-8 编码是一个不错的选择。


UTF-8 兼容 ASCII,代码中的大部分字符可以用一个字节保存;另外 UTF-8 基于 Unicode,支持全世界的字符,我们编写的代码可以给全球的程序员使用,真正做到技术无国界。


常见的 IDE 或者编辑器使用的编码

绝大多数的编译器,如:Xcode、Sublime、Text、Gedit、Vim等,在创建源文件时一般也默认使用 UTF-8 编码。

奇葩 Visual Studio 它默认使用本地编码来创建源文件。

所谓本地编码,就是像 GBK、Big5、Shift-JIS 等这样的国家编码(地区编码);针对不同国家发行的操作系统,默认的本地编码一般不同。简体中文本的 Windows 默认的本地编码是 GBK。

这就导致 Visual Studio在上传github时,出现中文乱码的现象。需要将文件强制转换成utf-8的编码模式。再进行上传。

ps :对于使用 Visual Studio 上传github的用户。可以使用本地代码转换器,将GBK->UTF-8,便于在github Desktop中查看(github Desktop 不会转码,中文会出现乱码情况)。不过 github网页的代码会自动转码,不会出现乱码。


程序编译时的编码

1) 微软编译器使用本地编码来保存这些字符。不同地区的 Windows 版本默认的本地编码不一样,所以,同样的窄字符串在不同的 Windows 版本下使用的编码也不一样。对于简体中文版的 Windows,使用的是 GBK 编码。


2) GCC、LLVM/Clang 编译器使用和源文件相同的编码来保存这些字符:如果源文件使用的是 UTF-8 编码,那么这些字符也使用 UTF-8 编码;如果源文件使用的是 GBK 编码,那么这些字符也使用 GBK 编码。


你看,对于代码中需要被处理的窄字符串,不同的编译器差别还是挺大的。不过可以肯定的是,这些字符始终都使用窄字符(多字节字符)编码。


对于 char 类型的窄字符串,微软编译器使用本地编码,GCC、LLVM/Clang 使用和源文件编码相同的编码。


四、编码字符集和运行字符集

站在专业的角度讲,源文件使用的字符集被称为编码字符集,也就是写代码的时候使用的字符集;程序中的字符或者字符串使用的字符集被称为运行字符集,也就是程序运行后使用的字符集。

源文件需要保存到硬盘,或者在网络上传输,使用的编码要尽量节省存储空间,同时要方便跨国交流,所以一般使用 UTF-8,这就是选择编码字符集的标准。

程序中的字符或者字符串,在程序运行后必须被载入到内存,才能进行后续的处理,对于这些字符来说,要尽量选用能够提高处理速度的编码,例如 UTF-16 和 UTF-32 编码就能够快速定位(查找)字符。

ps :编码字符集是站在存储和传输的角度,运行字符集是站在处理或者操作的角度,所以它们并不一定相同。