<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                # 附錄?A.?字符編碼 **目錄** + [1\. ASCII碼](apas01.html) + [2\. Unicode和UTF-8](apas02.html) + [3\. 在Linux C編程中使用Unicode和UTF-8](apas03.html) ## 1.?ASCII碼 ASCII碼的取值范圍是0~127,可以用7個bit表示。C語言中`char`型變量的大小規定為一字節,如果存放ASCII碼則只用到低7位,高位為0。以下是ASCII碼表: **圖?A.1.?ASCII碼表** ![ASCII碼表](https://box.kancloud.cn/2016-04-02_56ff80dc07a4f.png) 絕大多數計算機的一個字節是8位,取值范圍是0~255,而ASCII碼并沒有規定編號為128~255的字符,為了能表示更多字符,各廠商制定了很多種ASCII碼的擴展規范。注意,雖然通常把這些規范稱為擴展ASCII碼(Extended ASCII),但其實它們并不屬于ASCII碼標準。例如以下這種擴展ASCII碼由IBM制定,在字符終端下被廣泛采用,其中包含了很多表格邊線字符用來畫界面。 **圖?A.2.?IBM的擴展ASCII碼表** ![IBM的擴展ASCII碼表](https://box.kancloud.cn/2016-04-02_56ff80dc19d28.png) 在圖形界面中最廣泛使用的擴展ASCII碼是ISO-8859-1,也稱為Latin-1,其中包含歐洲各國語言中最常用的非英文字母,但畢竟只有128個字符,某些語言中的某些字母沒有包含。如下表所示。 **圖?A.3.?ISO-8859-1** ![ISO-8859-1](https://box.kancloud.cn/2016-04-02_56ff80dc2900e.png) 編號為128~159的是一些控制字符,在上表中沒有列出。 ## 2.?Unicode和UTF-8 為了統一全世界各國語言文字和專業領域符號(例如數學符號、樂譜符號)的編碼,ISO制定了ISO 10646標準,也稱為UCS(Universal Character Set)。UCS編碼的長度是31位,可以表示2<sup>31</sup>個字符。如果兩個字符編碼的高位相同,只有低16位不同,則它們屬于一個平面(Plane),所以一個平面由2<sup>16</sup>個字符組成。目前常用的大部分字符都位于第一個平面(編碼范圍是U-00000000~U-0000FFFD),稱為BMP(Basic Multilingual Plane)或Plane 0,為了向后兼容,其中編號為0~256的字符和Latin-1相同。UCS編碼通常用U-xxxxxxxx這種形式表示,而BMP的編碼通常用U+xxxx這種形式表示,其中x是十六進制數字。在ISO制定UCS的同時,另一個由廠商聯合組織也在著手制定這樣的編碼,稱為Unicode,后來兩家聯手制定統一的編碼,但各自發布各自的標準文檔,所以UCS編碼和Unicode碼是相同的。 有了字符編碼,另一個問題就是這樣的編碼在計算機中怎么表示。現在已經不可能用一個字節表示一個字符了,最直接的想法就是用四個字節表示一個字符,這種表示方法稱為UCS-4或UTF-32,UTF是Unicode Transformation Format的縮寫。一方面這樣比較浪費存儲空間,由于常用字符都集中在BMP,高位的兩個字節通常是0,如果只用ASCII碼或Latin-1,高位的三個字節都是0。另一種比較節省存儲空間的辦法是用兩個字節表示一個字符,稱為UCS-2或UTF-16,這樣只能表示BMP中的字符,但BMP中有一些擴展字符,可以用兩個這樣的擴展字符表示其它平面的字符,稱為Surrogate Pair。無論是UTF-32還是UTF-16都有一個更嚴重的問題是和C語言不兼容,在C語言中0字節表示字符串結尾,庫函數`strlen`、`strcpy`等等都依賴于這一點,如果字符串用UTF-32存儲,其中有很多0字節并不表示字符串結尾,這就亂套了。 UNIX之父Ken Thompson提出的UTF-8編碼很好地解決了這些問題,現在得到廣泛應用。UTF-8具有以下性質: * 編碼為U+0000~U+007F的字符只占一個字節,就是0x00~0x7F,和ASCII碼兼容。 * 編碼大于U+007F的字符用2~6個字節表示,每個字節的最高位都是1,而ASCII碼的最高位都是0,因此非ASCII碼字符的表示中不會出現ASCII碼字節(也就不會出現0字節)。 * 用于表示非ASCII碼字符的多字節序列中,第一個字節的取值范圍是0xC0~0xFD,根據它可以判斷后面有多少個字節也屬于當前字符的編碼。后面每個字節的取值范圍都是0x80~0xBF,見下面的詳細說明。 * UCS定義的所有2<sup>31</sup>個字符都可以用UTF-8編碼表示出來。 * UTF-8編碼最長6個字節,BMP字符的UTF-8編碼最長三個字節。 * 0xFE和0xFF這兩個字節在UTF-8編碼中不會出現。 具體來說,UTF-8編碼有以下幾種格式: U-00000000?–?U-0000007F:? 0xxxxxxx U-00000080?–?U-000007FF:? 110xxxxx?10xxxxxx U-00000800?–?U-0000FFFF:? 1110xxxx?10xxxxxx?10xxxxxx U-00010000?–?U-001FFFFF:? 11110xxx?10xxxxxx?10xxxxxx?10xxxxxx U-00200000?–?U-03FFFFFF:? 111110xx?10xxxxxx?10xxxxxx?10xxxxxx?10xxxxxx U-04000000?–?U-7FFFFFFF:? 1111110x?10xxxxxx?10xxxxxx?10xxxxxx?10xxxxxx?10xxxxxx 第一個字節要么最高位是0(ASCII字節),要么最高兩位都是1,最高位之后1的個數決定后面有多少個字節也屬于當前字符編碼,例如111110xx,最高位之后還有四個1,表示后面有四個字節也屬于當前字符的編碼。后面每個字節的最高兩位都是10,可以和第一個字節區分開。這樣的設計有利于誤碼同步,例如在網絡傳輸過程中丟失了幾個字節,很容易判斷當前字符是不完整的,也很容易找到下一個字符從哪里開始,結果頂多丟掉一兩個字符,而不會導致后面的編碼解釋全部混亂了。上面的格式中標為x的位就是UCS編碼,最后一種6字節的格式中x位有31個,可以表示31位的UCS編碼,UTF-8就像一列火車,第一個字節是車頭,后面每個字節是車廂,其中承載的貨物是UCS編碼。UTF-8規定承載的UCS編碼以大端表示,也就是說第一個字節中的x是UCS編碼的高位,后面字節中的x是UCS編碼的低位。 例如U+00A9(?字符)的二進制是10101001,編碼成UTF-8是11000010 10101001(0xC2 0xA9),但不能編碼成11100000 10000010 10101001,UTF-8規定每個字符只能用盡可能少的字節來編碼。 ## 3.?在Linux C編程中使用Unicode和UTF-8 目前各種Linux發行版都支持UTF-8編碼,當前系統的語言和字符編碼設置保存在一些環境變量中,可以通過`locale`命令查看: ``` $ locale LANG=en_US.UTF-8 LC_CTYPE="en_US.UTF-8" LC_NUMERIC="en_US.UTF-8" LC_TIME="en_US.UTF-8" LC_COLLATE="en_US.UTF-8" LC_MONETARY="en_US.UTF-8" LC_MESSAGES="en_US.UTF-8" LC_PAPER="en_US.UTF-8" LC_NAME="en_US.UTF-8" LC_ADDRESS="en_US.UTF-8" LC_TELEPHONE="en_US.UTF-8" LC_MEASUREMENT="en_US.UTF-8" LC_IDENTIFICATION="en_US.UTF-8" LC_ALL= ``` 常用漢字也都位于BMP中,所以一個漢字的存儲通常占3個字節。例如編輯一個C程序: ``` #include <stdio.h> int main(void) { printf("你好\n"); return 0; } ``` 源文件是以UTF-8編碼存儲的: ``` $ od -tc nihao.c 0000000 # i n c l u d e < s t d i o . 0000020 h > \n \n i n t m a i n ( v o i 0000040 d ) \n { \n \t p r i n t f ( " 344 275 0000060 240 345 245 275 \ n " ) ; \n \t r e t u r 0000100 n 0 ; \n } \n 0000107 ``` 其中八進制的`344 375 240`(十六進制`e4 bd a0`)就是“你”的UTF-8編碼,八進制的`345 245 275`(十六進制`e5 a5 bd`)就是“好”。把它編譯成目標文件,`"你好\n"`這個字符串就成了這樣一串字節:`e4 bd a0 e5 a5 bd 0a 00`,漢字在其中仍然是UTF-8編碼的,一個漢字占3個字節,這種字符在C語言中稱為多字節字符(Multibyte Character)。運行這個程序相當于把這一串字節`write`到當前終端的設備文件。如果當前終端的驅動程序能夠識別UTF-8編碼就能打印出漢字,如果當前終端的驅動程序不能識別UTF-8編碼(比如一般的字符終端)就打印不出漢字。也就是說,像這種程序,識別漢字的工作既不是由C編譯器做的也不是由`libc`做的,C編譯器原封不動地把源文件中的UTF-8編碼復制到目標文件中,`libc`只是當作以0結尾的字符串原封不動地`write`給內核,識別漢字的工作是由終端的驅動程序做的。 但是僅有這種程度的漢字支持是不夠的,有時候我們需要在C程序中操作字符串里的字符,比如求字符串`"你好\n"`中有幾個漢字或字符,用`strlen`就不靈了,因為`strlen`只看結尾的0字節而不管字符串里存的是什么,求出來的是字節數7。為了在程序中操作Unicode字符,C語言定義了寬字符(Wide Character)類型`wchar_t`和一些庫函數。在字符常量或字符串字面值前面加一個L就表示寬字符常量或寬字符串,例如定義`wchar_t c = L'你';`,變量`c`的值就是漢字“你”的31位UCS編碼,而`L"你好\n"`就相當于`{L'你', L'好', L'\n', 0}`,`wcslen`函數就可以取寬字符串中的字符個數。看下面的程序: ``` #include <stdio.h> #include <locale.h> int main(void) { if (!setlocale(LC_CTYPE, "")) { fprintf(stderr, "Can't set the specified locale! " "Check LANG, LC_CTYPE, LC_ALL.\n"); return 1; } printf("%ls", L"你好\n"); return 0; } ``` 寬字符串`L"你好\n"`在源代碼中當然還是存成UTF-8編碼的,但編譯器會把它變成4個UCS編碼`0x00004f60 0x0000597d 0x0000000a 0x00000000`保存在目標文件中,按小端存儲就是`60 4f 00 00 7d 59 00 00 0a 00 00 00 00 00 00 00`,用`od`命令查看目標文件應該能找到這些字節。 ``` $ gcc hihao.c $ od -tx1 a.out ``` `printf`的`%ls`轉換說明表示把后面的參數按寬字符串解釋,不是見到0字節就結束,而是見到UCS編碼為0的字符才結束,但是要`write`到終端仍然需要以多字節編碼輸出,這樣終端驅動程序才能識別,所以`printf`在內部把寬字符串轉換成多字節字符串再`write`出去。事實上,C標準并沒有規定多字節字符必須以UTF-8編碼,也可以使用其它的多字節編碼,在運行時根據環境變量確定當前系統的編碼,所以在程序開頭需要調用`setlocale`獲取當前系統的編碼設置,如果當前系統是UTF-8的,`printf`就把UCS編碼轉換成UTF-8編碼的多字節字符串再`write`出去。一般來說,程序在做內部計算時通常以寬字符編碼,如果要存盤或者輸出給別的程序,或者通過網絡發給別的程序,則采用多字節編碼。 關于Unicode和UTF-8本節只介紹了最基本的概念,部分內容出自[[Unicode FAQ]](bi01.html#bibli.unicodefaq "UTF-8 and Unicode FAQ, http://www.cl.cam.ac.uk/~mgk25/unicode.html"),讀者可進一步參考這篇文章。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看