-
Notifications
You must be signed in to change notification settings - Fork 0
/
apas02.html
8 lines (8 loc) · 7.18 KB
/
apas02.html
1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>2. Unicode和UTF-8</title><link rel="stylesheet" href="styles.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.73.2" /><link rel="start" href="index.html" title="Linux C编程一站式学习" /><link rel="up" href="apa.html" title="附录 A. 字符编码" /><link rel="prev" href="apas01.html" title="1. ASCII码" /><link rel="next" href="apas03.html" title="3. 在Linux C编程中使用Unicode和UTF-8" /></head><body><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">2. Unicode和UTF-8</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="apas01.html">上一页</a> </td><th width="60%" align="center">附录 A. 字符编码</th><td width="20%" align="right"> <a accesskey="n" href="apas03.html">下一页</a></td></tr></table><hr /></div><div class="sect1" lang="zh-cn" xml:lang="zh-cn"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="id2906489"></a>2. Unicode和UTF-8</h2></div></div></div><p>为了统一全世界各国语言文字和专业领域符号(例如数学符号、乐谱符号)的编码,ISO制定了ISO 10646<a id="id2906502" class="indexterm"></a>标准,也称为UCS(Universal Character Set)<a id="id2906510" class="indexterm"></a>。UCS编码的长度是31位,可以表示2<sup>31</sup>个字符。如果两个字符编码的高位相同,只有低16位不同,则它们属于一个平面(Plane)<a id="id2906524" class="indexterm"></a>,所以一个平面由2<sup>16</sup>个字符组成。目前常用的大部分字符都位于第一个平面(编码范围是U-00000000~U-0000FFFD),称为BMP(Basic Multilingual Plane)<a id="id2906537" class="indexterm"></a>或Plane 0,为了向后兼容,其中编号为0~256的字符和Latin-1相同。UCS编码通常用U-xxxxxxxx这种形式表示,而BMP的编码通常用U+xxxx这种形式表示,其中x是十六进制数字。在ISO制定UCS的同时,另一个由厂商联合组织也在着手制定这样的编码,称为Unicode<a id="id2906555" class="indexterm"></a>,后来两家联手制定统一的编码,但各自发布各自的标准文档,所以UCS编码和Unicode码是相同的。</p><p>有了字符编码,另一个问题就是这样的编码在计算机中怎么表示。现在已经不可能用一个字节表示一个字符了,最直接的想法就是用四个字节表示一个字符,这种表示方法称为UCS-4<a id="id2906571" class="indexterm"></a>或UTF-32<a id="id2906578" class="indexterm"></a>,UTF是Unicode Transformation Format<a id="id2906586" class="indexterm"></a>的缩写。一方面这样比较浪费存储空间,由于常用字符都集中在BMP,高位的两个字节通常是0,如果只用ASCII码或Latin-1,高位的三个字节都是0。另一种比较节省存储空间的办法是用两个字节表示一个字符,称为UCS-2<a id="id2906598" class="indexterm"></a>或UTF-16<a id="id2906605" class="indexterm"></a>,这样只能表示BMP中的字符,但BMP中有一些扩展字符,可以用两个这样的扩展字符表示其它平面的字符,称为Surrogate Pair<a id="id2906615" class="indexterm"></a>。无论是UTF-32还是UTF-16都有一个更严重的问题是和C语言不兼容,在C语言中0字节表示字符串结尾,库函数<code class="literal">strlen</code>、<code class="literal">strcpy</code>等等都依赖于这一点,如果字符串用UTF-32存储,其中有很多0字节并不表示字符串结尾,这就乱套了。</p><p>UNIX之父Ken Thompson提出的UTF-8<a id="id2906642" class="indexterm"></a>编码很好地解决了这些问题,现在得到广泛应用。UTF-8具有以下性质:</p><div class="itemizedlist"><ul type="disc"><li><p>编码为U+0000~U+007F的字符只占一个字节,就是0x00~0x7F,和ASCII码兼容。</p></li><li><p>编码大于U+007F的字符用2~6个字节表示,每个字节的最高位都是1,而ASCII码的最高位都是0,因此非ASCII码字符的表示中不会出现ASCII码字节(也就不会出现0字节)。</p></li><li><p>用于表示非ASCII码字符的多字节序列中,第一个字节的取值范围是0xC0~0xFD,根据它可以判断后面有多少个字节也属于当前字符的编码。后面每个字节的取值范围都是0x80~0xBF,见下面的详细说明。</p></li><li><p>UCS定义的所有2<sup>31</sup>个字符都可以用UTF-8编码表示出来。</p></li><li><p>UTF-8编码最长6个字节,BMP字符的UTF-8编码最长三个字节。</p></li><li><p>0xFE和0xFF这两个字节在UTF-8编码中不会出现。</p></li></ul></div><p>具体来说,UTF-8编码有以下几种格式:</p><div class="literallayout"><p>U-00000000 – U-0000007F: 0xxxxxxx<br />
U-00000080 – U-000007FF: 110xxxxx 10xxxxxx<br />
U-00000800 – U-0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx<br />
U-00010000 – U-001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx<br />
U-00200000 – U-03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx<br />
U-04000000 – U-7FFFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx</p></div><p>第一个字节要么最高位是0(ASCII字节),要么最高两位都是1,最高位之后1的个数决定后面有多少个字节也属于当前字符编码,例如111110xx,最高位之后还有四个1,表示后面有四个字节也属于当前字符的编码。后面每个字节的最高两位都是10,可以和第一个字节区分开。这样的设计有利于误码同步,例如在网络传输过程中丢失了几个字节,很容易判断当前字符是不完整的,也很容易找到下一个字符从哪里开始,结果顶多丢掉一两个字符,而不会导致后面的编码解释全部混乱了。上面的格式中标为x的位就是UCS编码,最后一种6字节的格式中x位有31个,可以表示31位的UCS编码,UTF-8就像一列火车,第一个字节是车头,后面每个字节是车厢,其中承载的货物是UCS编码。UTF-8规定承载的UCS编码以大端表示,也就是说第一个字节中的x是UCS编码的高位,后面字节中的x是UCS编码的低位。</p><p>例如U+00A9(©字符)的二进制是10101001,编码成UTF-8是11000010 10101001(0xC2 0xA9),但不能编码成11100000 10000010 10101001,UTF-8规定每个字符只能用尽可能少的字节来编码。</p></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="apas01.html">上一页</a> </td><td width="20%" align="center"><a accesskey="u" href="apa.html">上一级</a></td><td width="40%" align="right"> <a accesskey="n" href="apas03.html">下一页</a></td></tr><tr><td width="40%" align="left" valign="top">1. ASCII码 </td><td width="20%" align="center"><a accesskey="h" href="index.html">起始页</a></td><td width="40%" align="right" valign="top"> 3. 在Linux C编程中使用Unicode和UTF-8</td></tr></table></div></body></html>