Linux C編程中使用Unicode和UTF-8

來源:互聯網
上載者:User

3. 在Linux C編程中使用Unicode和UTF-8

全國嵌入式人才培訓基地
3. 在Linux C編程中使用Unicode和UTF-8
上一頁  附錄 A. 字元編碼  下一頁
3. 在Linux C編程中使用Unicode和UTF-8 請點評

目前各種Linux發行版都支援UTF-8編碼,當前系統的語言和字元編碼設定儲存在一些環境變數中,可以通過locale命令查看:

$ localeLANG=en_US.UTF-8LC_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   i0000040   d   )  \n   {  \n  \t   p   r   i   n   t   f   (   " 344 2750000060 240 345 245 275   \   n   "   )   ;  \n  \t   r   e   t   u   r0000100   n       0   ;  \n   }  \n0000107

其中八進位的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],讀者可進一步參考這篇文章。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.