C语言:字符编码
C语言是 70 年代的产物,那个时候只有 ASCII,各个国家的字符编码都还未成熟,所以C语言不可能从底层支持 GB2312、GBK、Big5、Shift-JIS 等国家编码,也不可能支持 Unicode 字符集。
稍微有点C语言基本功的读者可能认为C语言使用 ASCII 编码,字符在存储时会转换成对应的 ASCII 码值,这也是错误的,你被大学老师和教材误导了!在C语言中,只有 char 类型的窄字符才使用 ASCII 编码,char 类型的窄字符串、wchar_t 类型的宽字符和宽字符串都不使用 ASCII 编码!
wchar_t 类型的宽字符和宽字符串使用 UTF-16 或者 UTF-32 编码,这个在上节已经讲到了,现在只剩下 char 类型的窄字符串(下面称为窄字符串)没有讲了,这就是本节的重点。
对于窄字符串,C语言并没有规定使用哪一种特定的编码,只要选用的编码能够适应当前的环境即可,所以,窄字符串的编码与操作系统和编译器有关。
但是,可以肯定的说,在现代计算机中,窄字符串已经不再使用 ASCII 编码了,因为 ASCII 编码只能显示字母、数字等英文字符,对汉语、日语、韩语等其它地区的字符无能为力。
讨论窄字符串的编码要从以下两个方面下手。
源文件使用什么编码
源文件用来保存我们编写的代码,它最终会被存储到本地硬盘,或者远程服务器,这个时候就要尽量压缩文件体积,以节省硬盘空间或者网络流量,而代码中大部分的字符都是 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。
对于编译器来说,它往往支持多种编码格式的源文件。微软编译器、GCC、LLVM/Clang(内嵌于 Xcode 中)都支持 UTF-8 和本地编码的源文件,不过微软编译器还支持 UTF-16 编码的源文件。如果考虑到源文件的通用性,就只能使用 UTF-8 和本地编码了。
窄字符串使用什么编码
前面讲到,用 puts 或者 printf 可以输出窄字符串,代码如下:
- #include <stdio.h>
- int main()
- {
- puts("C语言中文网");
- printf("http://abceng.net");
- return 0;
- }
"C语言中文网"和"http://abceng.net"就是需要被处理的窄字符串,程序运行后,它们会被载入到内存中。你看,这里面还包含了中文,肯定不能使用 ASCII 编码了。
1) 微软编译器使用本地编码来保存这些字符。不同地区的 Windows 版本默认的本地编码不一样,所以,同样的窄字符串在不同的 Windows 版本下使用的编码也不一样。对于简体中文版的 Windows,使用的是 GBK 编码。
2) GCC、LLVM/Clang 编译器使用和源文件相同的编码来保存这些字符:如果源文件使用的是 UTF-8 编码,那么这些字符也使用 UTF-8 编码;如果源文件使用的是 GBK 编码,那么这些字符也使用 GBK 编码。
你看,对于代码中需要被处理的窄字符串,不同的编译器差别还是挺大的。不过可以肯定的是,这些字符始终都使用窄字符(多字节字符)编码。
正是由于这些字符使用 UTF-8、GBK 等编码,而不是使用 ASCII 编码,所以它们才能包含中文。
那么,为什么很多初学者会误认为C语言使用 ASCII 编码呢?
不管是在课堂跟着老师学习,还是通过互联网自学,初学者都是从处理英文开始的,对于英文来说,使用 GBK、UTF-8、ASCII 都是一样的,GBK、UTF-8 都兼容 ASCII,初学者根本察觉不出用了哪种编码。
另外,很多大学老师和书籍作者也经常会念叨,字符在存储时会被转换成对应的 ASCII 码,在读取时又会从 ASCII 码转换成对应的字符实体,大家需要熟悉 ASCII 编码,它是C语言处理字符的基础,这从很大程度上给初学者造成一种错误印象:C语言和 ASCII 编码是绑定的,C语言使用 ASCII 编码。
总结
对于 char 类型的窄字符,始终使用 ASCII 编码。
对于 wchar_t 类型的宽字符和宽字符串,使用 UTF-16 或者 UTF-32 编码,它们都是基于 Unicode 字符集的。
对于 char 类型的窄字符串,微软编译器使用本地编码,GCC、LLVM/Clang 使用和源文件编码相同的编码。
另外,处理窄字符和处理宽字符使用的函数也不一样:
- <stdio.h> 头文件中的 putchar、puts、printf 函数只能用来处理窄字符;
- <wchar.h> 头文件中的 putwchar、wprintf 函数只能用来处理宽字符。
你看,仅仅是字符的处理,C语言就能玩出这么多花样,让人捉摸不透,不容易学习。这是因为,C语言是一种较为底层和古老的语言,既有历史遗留问题,又有贴近计算机底层的特性。不过,一旦搞明白这些繁杂的底层问题,你的编程内功将精进一个层次,这也许就是学习C语言的乐趣。
【拓展】编码字符集和运行字符集
站在专业的角度讲,源文件使用的字符集被称为编码字符集,也就是写代码的时候使用的字符集;程序中的字符或者字符串使用的字符集被称为运行字符集,也就是程序运行后使用的字符集。
源文件需要保存到硬盘,或者在网络上传输,使用的编码要尽量节省存储空间,同时要方便跨国交流,所以一般使用 UTF-8,这就是选择编码字符集的标准。
程序中的字符或者字符串,在程序运行后必须被载入到内存,才能进行后续的处理,对于这些字符来说,要尽量选用能够提高处理速度的编码,例如 UTF-16 和 UTF-32 编码就能够快速定位(查找)字符。
编码字符集是站在存储和传输的角度,运行字符集是站在处理或者操作的角度,所以它们并不一定相同。
C语言:字符编码的更多相关文章
- C语言字符编码处理
一.字符编码识别 1.简介 uchardet是一个开源的用于文本编码检测的C语言库,其功能模块是用C++实现的,通过一定数量的字符样本独立的分析出文本的编码,当前已经支持UTF-8/GB13080/B ...
- C语言-字符编码转换:UTF与GB2312
依赖库libiconv,libiconv库的交叉编译不做描述,网上很多 #include <stdio.h> #include <stdlib.h> #include < ...
- HTML语言字符编码
! ! — 惊叹号Exclamation mark ” " " 双引号Quotation mark # # — 数字标志Number sign $ $ — 美元标志Dollar s ...
- day 08字符编码 文件处理
字符编码1.软件启动流程(打开notepad++文档)从硬盘将软件加载到内存上加载test.txt到内存中执行notepad++的代码,将test.txt打到屏幕上 python解释器也是一个应用软件 ...
- python基础之Day7part2 史上最清晰字符编码理解
二.字符编码 基础知识: 文本编辑器存取文件原理与py执行原理异同: 存/写:进入文本编辑器 写内容 保存后 内存数据刷到硬盘 取/读:进入文本编辑器 找到内容 从硬盘读到内存 notepad把文件内 ...
- 操作系统和程序设计语言的API使用的字符编码分析
1.Java的运行环境中,String是什么编码? 使用java做程序设计语言,字符编码是和jvm相关的,和操作系统无关. java默认的编码是jvm在安装的时候就确定了的,它是根据你的系统的环境确 ...
- Swift3.0语言教程删除字符与处理字符编码
Swift3.0语言教程删除字符与处理字符编码 Swift3.0语言教程删除字符 Swift3.0语言教程删除字符与处理字符编码,在字符串中,如果开发者有不需要使用的字符,就可以将这些字符删除.在NS ...
- 【miscellaneous】【C/C++语言】UTF8与GBK字符编码之间的相互转换
UTF8与GBK字符编码之间的相互转换 C++ UTF8编码转换 CChineseCode 一 预备知识 1,字符:字符是抽象的最小文本单位.它没有固定的形状(可能是一个字形),而且没有值." ...
- python学习笔记(基础一:'hello world'、变量、字符编码)
第一个python程序: Hello World程序 windows命令行中输入:python,进入python交互器,也可以称为解释器. print("Hello World!" ...
随机推荐
- MindSpore循环神经网络
MindSpore循环神经网络 一. 神经网络的组成 神经元模型:首先简单的了解以下构成神经网络的最基础单元:神经元.每个神经元与其它神经元相连,处于激活状态时,就会向相连的神经元发送相应信号.从而改 ...
- MLIR中间表示和编译器框架
MLIR中间表示和编译器框架 TensorFlow生态系统包含许多在软件和硬件堆栈的多个级别上运行的编译器和优化器.作为TensorFlow的日常用户,使用不同类型的硬件(GPU,TPU,移动设备)时 ...
- MindSpore:自动微分
MindSpore:自动微分 作为一款「全场景 AI 框架」,MindSpore 是人工智能解决方案的重要组成部分,与 TensorFlow.PyTorch.PaddlePaddle 等流行深度学习框 ...
- 英伟达TRTTorch
英伟达TRTTorch PyTorch JIT的提前(AOT)编译Ahead of Time (AOT) compiling for PyTorch JIT TRTorch是PyTorch / Tor ...
- CUDA 8的混合精度编程
CUDA 8的混合精度编程 Volta和Turing GPU包含 Tensor Cores,可加速某些类型的FP16矩阵数学运算.这样可以在流行的AI框架内更快,更轻松地进行混合精度计算.要使用Ten ...
- CVPR2020:三维点云无监督表示学习的全局局部双向推理
CVPR2020:三维点云无监督表示学习的全局局部双向推理 Global-Local Bidirectional Reasoning for Unsupervised Representation L ...
- ARMed解决方案对DSP的战争
ARMed解决方案对DSP的战争 ARM体系结构简化了数字信号处理 ARM与数字信号处理(DSP)有什么关系? ARM似乎在处理领域处于领先地位.该处理器已将其视为其最大的细分市场之一,这主要是由于该 ...
- NOIP模拟测试23「mine·water·gcd」
mine 题解 一道比较水的dp 考试因为初始化挂掉了只有$80$分 代码有注释 #include<bits/stdc++.h> using namespace std; //无脑dp # ...
- Mysql8关于hashjoin的代码处理方式
Mysql8关于hashjoin的代码处理方式 目录 Mysql8关于hashjoin的代码处理方式 1 表的Schema如下所示: 2 HashJoin代码实现 3 总结 1 表的Schema如下所 ...
- 记Aspose.Word的使用中出现的问题
最近实现一个功能,具体需求就是把数据库中的内容转换成word文档,文档中需要包含标题.目录以及表格信息. 这里我使用的是Aspose.Word类,这是一个很强大的文档操作工具包,实现了所有操作文档的所 ...