🌱UTF-8与Unicode码点的关系
什么是码点
想象一下,世界上有那么多语言,那么多字符(比如 A, 中, β, 😂 等等)。我们需要一种方法给每一个字符一个唯一的、标准的编号,方便计算机识别和处理。这个唯一的编号,就叫做 码点 (Code Point)。 Unicode是目前最权威的字符编码标准,它为全世界几乎所有的字符都分配了一个码点。
码点格式
码点通常写作 U+,后面跟着一组十六进制数字,如: A -> U+0041 中 -> U+4E2D 😂 -> U+1F602
码点是字符在Unicode中唯一的数字标识,它只关心这个字符是什么,不关心这个字符在计算机内如何存储。
UTF-8如何存储码点
UTF8是一种编码规则,定义了如何将一个Unicode码点转换成一个或多个字节的二进制序列,以便在计算机中存储和传输。
UTF8的主要特点是可变长度编码:
- 对于英文字符,码点数值很小,UTF8只用一个字节来表示它,这与ASCII完全兼容,且节省空间。
- 拉丁文用两个字节表示。
- 中日韩文字用三个字节表示:中 (码点 U+4E2D) -> UTF-8 编码为 11100100 10111010 10101101 (十六进制 E4 BA AD)。
- 不常用的字符和表情符号,用四个字节表示。
如何判断一个UTF8字符占用几个字节
和很多协议一样,用开头的几位(或几字节)来表示长度。
如果字节以0开头,这一定是一个单字节字符; 如果字节以110开头,这一定是一个2字节字符的起始字节; 如果字节以1110开头,这一定是一个3字节字符的起始字节; 如果字节以11110开头,这一定是一个4字节字符的起始字节; 如果字节以10开头,代表这是多字节字符的后续字节。
这种编码的优点:如果因为传输错误丢失了一些字节,从中间的某个字节开始读取,因为以10开头,你可以马上知道这不是一个字符的开头。同理,在其他应用比如文本编辑器中,你也可以用字节开头来判断。
如何判断在代码中使用的编码
在大多数现代开发环境下,最佳实践是: 将.c/.cpp文件保存为UTF8编码,然后不做任何特殊设置。 在这种情况下,代码中定义的字符串会在内存中存储为UTF8编码的字节序列。
实际上C/C++标准定义了两个字符集的概念,编译器会在这两者之间进行转换。
- 源代码字符集 指的是.cpp文件保存使用的编码,如UTF8、GBK等。编译器需要知道源代码的编码格式,这样才能正确解码。
- 执行字符集 指的是最终生成的可执行文件中,字符串应该以何种编码的字节序列形式存在。也就是最终在内存中,char数组里实际存储的字节编码格式。
所以,如果什么都不设置,大多数现代编译环境都会默认这两个字符集都是UTF8,这也就有了开始的结论。