最初的unicode編碼是固定長度的,16位,也就是2兩個字節表明一個字符,這樣一共能夠表示65536個字符。顯然,這樣要表示各類語言中全部的字符是遠遠不夠的。Unicode4.0規範考慮到了這種狀況,定義了一組附加字符編碼,附加字符編碼採用2個16位來表示,這樣最多能夠定義1048576個附加字符,目前unicode4.0只定義了45960個附加字符。java
Unicode只是一個編碼規範,目前實際實現的unicode編碼只要有三種:UTF-8,UCS-2和UTF-16,三種unicode字符集之間能夠按照規範進行轉換。數據庫
UTF-8windows
UTF-8是一種8位的unicode字符集,編碼長度是可變的,而且是ASCII字符集的嚴格超集,也就是說ASCII中每一個字符的編碼在UTF-8中是徹底同樣的。UTF-8字符集中,一個字符多是1個字節,2個字節,3個字節或者4個字節長。通常來講,歐洲的字母字符長度爲1到2個字節,而亞洲的大部分字符則是3個字節,附加字符爲4個字節長。數組
Unix平臺中廣泛支持UTF-8字符集,HTML和大多數瀏覽器也支持UTF-8,而window和java則支持UCS-2。瀏覽器
UTF-8的主要優勢:函數
UCS-2字體
UCS-2是固定長度爲16位的unicode字符集。每一個字符都是2個字節,UCS-2只支持unicode3.0,因此不支持附加字符。編碼
UCS-2的優勢:操作系統
UTF-16設計
UTF-16也是一種16位編碼的字符集。實際上,UTF-16就是UCS-2加上附加字符的支持,也就是符合unicode4.0規範的UCS-2。因此UTF-16是UCS-2的嚴格超集。
UTF-16中的字符,要麼是2個字節,要麼是4個字節表示的。UTF-16主要在windows2000以上版本使用。
UTF-16相對UTF-8的優勢,和UCS-2是一致的。
Oracle從7.0開始提供對Unicode的支持。Oracle個版本的unicode字符集支主要有:
AL32UTF8
一種UTF-8編碼的字符集,支持最新的unicode4.0標準。字符長度爲1,2或者3個字節,附加字符則爲4字節長。
UTF8
支持unicode3.0的UTF-8編碼方式。因爲附加字符是在unicode3.1中提出的,UTF8不支持附加字符。可是unicode3.0已經爲附加字符預留了編碼空間,因此即便在UTF8的數據庫中插入附加字符,也是能夠的,只是數據庫會將該字符分隔成兩部分,須要佔6個字符的長度。因此,若是須要支持附加字符,那麼建議將數據庫的字符集切換爲新的AL32UTF8。
UTF8可用於數據庫字符集,也可用於國家字符集。
UTFE
UTFE是基於EBCDIC平臺的unicode字符集,就像ASCII平臺上的UTF8同樣。不一樣的是,UTFE中,每一個字符可能佔1,2,3或者4個字節,而附加字符則須要2個4個字節,也就是8個字節來表示。
AL16UTF16
AL16UTF16是一種UTF-16編碼的unicode字符集,在Oracle中用於國家字符集。
AL24UTFFSS
該字符集只支持unicode1.1規範,在Oracle7.2~8i版本中使用,目前已經淘汰。
CString在Unicode下一個字節佔16bit,在ascii下佔8bit,改爲char數組後在什麼環境下都同樣的
編寫程序最好是:同一個源文件既能夠在UNICODE下編譯,又能夠在ANSI下編譯工程--設置--C/C++--預處理器,能夠定義標識符,如UNICODE,_UNICODE,標識是按ASCII編譯,仍是按UNICODE編譯#include <tchar.h>char定義所有 改爲TCHAR,TCHAR根據設置不一樣定義爲char或者wchar字符串加用TEXT宏,如TEXT("你好"),根據編譯器的設置不一樣,分別定義爲ANSI或者UNICODE版本字符串也大部分有其通用版本:最大長度版比標準版多一個參數,表示緩衝區的長度有v的其參數爲參數列表指針,使用va_list、va_start和va_end宏C提供的字符串函數: ASCII 寬字符 通用形式1.可變參數:標準版 sprintf swprintf _stprintf最大長度版 _snprintf _snwprintf _sntprintfWindowsNT版 wsprintfA wsprintfW wsprintf2.數組的指針做參數: 標準版 vsprintf vswprintf _vstprintf最大長度版 _vsnprintf _vsnwprintf _vsntprintfWindowsNT版 wvsprintfA wvsprintfW wvsprintf如下引用《Windows程序設計》美國標準早期計算機的字符碼是從Hollerith卡片(號稱不能被折迭、捲曲或毀傷)發展而來的,該卡片由Herman Hollerith發明並首次在1890年的美國人口普查中使用。6位字符碼系統BCDIC(Binary-Coded Decimal Interchange Code:二進制編碼十進制交換編碼)源自Hollerith代碼,在60年代逐步擴展爲8位EBCDIC,並一直是IBM大型主機的標準,但沒使用在其它地方。美國信息交換標準碼(ASCII:American Standard Code for Information Interchange)起始於50年代後期,最後完成於1967年。開發ASCII的過程當中,在字符長度是6位、7位仍是8位的問題上產生了很大的爭議。從可靠性的觀點來看不該使用替換字符,所以ASCII不能是6位編碼,但因爲費用的緣由也排除了8位版本的方案(當時每位的儲存空間成本仍很昂貴)。這樣,最終的字符碼就有26個小寫字母、26個大寫字母、10個數字、32個符號、33個句柄和一個空格,總共128個字符碼。ASCII如今記錄在ANSI X3.4-1986字符集-用於信息交換的7位美國國家標準碼(7-Bit ASCII:7-Bit American National Standard Code for Information Interchange),由美國國家標準協會(American National Standards Institute)發佈。圖2-1中所示的ASCII字符碼與ANSI文件中的格式類似。ASCII有許多優勢。例如,26個字母代碼是連續的(在EBCDIC代碼中就不是這樣的);大寫字母和小寫字母可經過改變一位數據而相互轉化;10個數字的代碼可從數值自己方便地獲得(在BCDIC代碼中,字符「0」的編碼在字符「9」的後面!)最棒的是,ASCII是一個很是可靠的標準。在鍵盤、視訊顯示卡、系統硬件、打印機、字體文件、操做系統和Internet上,其它標準都不如ASCII碼流行並且根深蒂固。 圖2-1 ASCII字符集國際方面ASCII的最大問題就是該縮寫的第一個字母。ASCII是一個真正的美國標準,因此它不能良好知足其它講英語國家的須要。例如英國的英鎊符號(£)在哪裏?英語使用拉丁(或羅馬)字母表。在使用拉丁語字母表的書寫語言中,英語中的單詞一般不多須要重音符號(或讀音符號)。即便那些傳統慣例加上讀音符號也無不當的英語單字,例如c鰋perate或者résumé,拼寫中沒有讀音符號也會被徹底接受。但在美國以南、以北,以及大西洋地區的許多國家,在語言中使用讀音符號很廣泛。這些重音符號最初是爲使拉丁字母表適合這些語言讀音不一樣的須要。在遠東或西歐的南部旅遊,您會遇到根本不使用拉丁字母的語言,例如希臘語、希伯來語、阿拉伯語和俄語(使用斯拉夫字母表)。若是您向東走得更遠,就會發現中國象形漢字,日本和朝鮮也採用漢字系統。ASCII的歷史開始於1967年,此後它主要致力於克服其自身限制以更適合於非美國英語的其它語言。例如,1967年,國際標準化組織(ISO:International Standards Organization)推薦一個ASCII的變種,代碼0x40、0x5B、0x5C、0x5D、0x7B、0x7C和0x7D「爲國家使用保留」,而代碼0x5E、0x60和0x7E標爲「當國內要求的特殊字符須要八、9或10個空間位置時,可用於其它圖形符號」。這顯然不是一個最佳的國際解決方案,由於這並不能保證一致性。但這卻顯示了人們如何想盡辦法爲不一樣的語言來編碼的。擴展ASCII在小型計算機開發的初期,就已經嚴格地創建了8位字節。所以,若是使用一個字節來保存字符,則須要128個附加的字符來補充ASCII。1981年,當最初的IBM PC推出時,視訊卡的ROM中燒有一個提供256個字符的字符集,這也成爲IBM標準的一個重要組成部分。最初的IBM擴展字符集包括某些帶重音的字符和一個小寫希臘字母表(在數學符號中很是有用),還包括一些塊型和線狀圖形字符。附加的字符也被添加到ASCII控制字符的編碼位置,這是由於大多數控制字符都不是拿來顯示用的。該IBM擴展字符集被燒進無數顯示卡和打印機的ROM中,並被許多應用程序用於修飾其文字模式的顯示方式。不過,該字符集並無爲全部使用拉丁字母表的西歐語言提供足夠多的帶重音字符,並且也不適用於Windows。Windows不須要圖形字符,由於它有一個徹底圖形化的系統。在Windows 1.0(1985年11月發行)中,Microsoft沒有徹底放棄IBM擴展字符集,但它已退居第二重要位置。由於遵循了ANSI草案和ISO標準,純Windows字符集被稱做「ANSI字符集」。ANSI草案和ISO標準最終成爲ANSI/ISO 8859-1-1987,即「American National Standard for Information Processing-8-Bit Single-Byte Coded Graphic Character Sets-Part 1: Latin Alphabet No 1」,一般也簡寫爲「Latin 1」。在Windows 1.0的《Programmer's Reference》中印出了ANSI字符集的最第一版本,如圖2-2所示。 圖2-2 Windows ANSI字符集(基於ANSI/ISO 8859-1)空方框表示該位置未定義字符。這與ANSI/ISO 8859-1的最終定義一致。ANSI/ISO 8859-1僅顯示了圖形字符,而沒有控制字符,所以沒有定義DEL。此外,代碼0xA0定義爲一個非斷開的空格(這意味着在編排格式時,該字符不用於斷開一行),代碼0xAD是一個軟連字符(表示除非在行尾斷開單詞時使用,不然不顯示)。此外,ANSI/ISO 8859-1將代碼0xD7定義爲乘號(*),0xF7爲除號(/)。Windows中的某些字體也定義了從0x80到0x9F的某些字符,但這些不是ANSI/ISO 8859-1標準的一部分。MS-DOS 3.3(1987年4月發行)向IBM PC用戶引進了代碼頁(code page)的概念,Windows也使用此概念。代碼頁定義了字符的映像代碼。最初的IBM字符集被稱做代碼頁437,或者「MS-DOS Latin US)。代碼頁850就是「MS-DOS Latin 1」,它用附加的帶重音字母(但不是圖2-2所示的Latin 1 ISO/ANSI標準)代替了一些線形字符。其它代碼頁被其它語言定義。最低的128個代碼老是相同的;較高的128個代碼取決於定義代碼頁的語言。在MS-DOS中,若是用戶爲PC的鍵盤、顯示卡和打印機指定了一個代碼頁,而後在PC上建立、編輯和打印文件,一切都很正常,每件事都會保持一致。然而,若是用戶試圖與使用不一樣代碼頁的用戶交換文件,或者在機器上改變代碼頁,就會產生問題。字符碼與錯誤的字符相關聯。應用程序可以將代碼頁信息與文件一塊兒保存來試圖減小問題的產生,但該策略包括了某些在代碼頁間轉換的工做。雖然代碼頁最初僅提供了不包括帶重音符號字母的附加拉丁字符集,但最終代碼頁的較高的128個字符仍是包括了完整的非拉丁字母,例如希伯來語、希臘語和斯拉夫語。天然,如此多樣會致使代碼頁變得混亂;若是少數帶重音的字母未正確顯示,那麼整個文字便會混亂不堪而不可閱讀。代碼頁的擴展正是基於全部這些緣由,可是還不夠。斯拉夫語的MS-DOS代碼頁855與斯拉夫語的Windows代碼頁1251以及斯拉夫語的Macintosh代碼頁10007不一樣。每一個環境下的代碼頁都是對該環境所做的標準字符集修正。IBM OS/2也支援多種EBCDIC代碼頁。但等一下,你會發現事情變得更糟糕。雙字節字符集迄今爲止,咱們已經看到了256個字符的字符集。但中國、日本和韓國的象形文字符號有大約21,000個。如何容納這些語言而仍保持和ASCII的某種兼容性呢?解決方案(若是這個說法正確的話)是雙字節字符集(DBCS:double-byte character set)。DBCS從256代碼開始,就像ASCII同樣。與任何行爲良好的代碼頁同樣,最初的128個代碼是ASCII。然而,較高的128個代碼中的某些老是跟隨着第二個字節。這兩個字節一塊兒(稱做首字節和跟隨字節)定義一個字符,一般是一個複雜的象形文字。雖然中文、日文和韓文共享一些相同的象形文字,但顯然這三種語言是不一樣的,並且常常是同一個象形文字在三種不一樣的語言中表明三件不一樣的事。Windows支持四個不一樣的雙字節字符集:代碼頁932(日文)、936(簡體中文)、949(韓語)和950(繁體漢字)。只有爲這些國家(地區)生產的Windows版本才支持DBCS。雙字符集問題並非說字符由兩個字節表明。問題在於一些字符(特別是ASCII字符)由1個字節表示。這會引發附加的程序設計問題。例如,字符串中的字符數不能由字符串的字節數決定。必須剖析字符串來決定其長度,並且必須檢查每一個字節以肯定它是否爲雙字節字符的首字節。若是有一個指向DBCS字符串中間的指針,那麼該字符串前一個字符的地址是什麼呢?慣用的解決方案是從開始的指針分析該字符串!Unicode解決方案咱們面臨的基本問題是世界上的書寫語言不能簡單地用256個8位代碼表示。之前的解決方案包括代碼頁和DBCS已被證實是不能知足須要的,並且也是笨拙的。那什麼纔是真正的解決方案呢?身爲程序寫做者,咱們經歷過這類問題。若是事情太多,用8位數值已經不能表示,那麼咱們就試更寬的值,例如16位值。並且這頗有趣的,正是Unicode被制定的緣由。與混亂的256個字符代碼映像,以及含有一些1字節代碼和一些2字節代碼的雙字節字符集不一樣,Unicode是統一的16位系統,這樣就容許表示65,536個字符。這對錶示全部字符及世界上使用象形文字的語言,包括一系列的數學、符號和貨幣單位符號的集合來講是充裕的。明白Unicode和DBCS之間的區別很重要。Unicode使用(特別在C程序設計語言環境裏)「寬字符集」。「Unicode中的每一個字符都是16位寬而不是8位寬。」在Unicode中,沒有單單使用8位數值的意義存在。相比之下,在雙字節字符集中咱們仍然處理8位數值。有些字節自身定義字符,而某些字節則顯示須要和另外一個字節共同定義一個字符。處理DBCS字符串很是雜亂,可是處理Unicode文字則像處理有秩序的文字。您也許會高興地知道前128個Unicode字符(16位代碼從0x0000到0x007F)就是ASCII字符,而接下來的128個Unicode字符(代碼從0x0080到0x00FF)是ISO 8859-1對ASCII的擴展。Unicode中不一樣部分的字符都一樣基於現有的標準。這是爲了便於轉換。希臘字母表使用從0x0370到0x03FF的代碼,斯拉夫語使用從0x0400到0x04FF的代碼,美國使用從0x0530到0x058F的代碼,希伯來語使用從0x0590到0x05FF的代碼。中國、日本和韓國的象形文字(總稱爲CJK)佔用了從0x3000到0x9FFF的代碼。Unicode的最大好處是這裏只有一個字符集,沒有一點含糊。Unicode其實是我的計算機行業中幾乎每一個重要公司共同合做的結果,而且它與ISO 10646-1標準中的代碼是一一對應的。Unicode的重要參考文獻是《The Unicode Standard,Version 2.0》(Addison-Wesley出版社,1996年)。這是一本特別的書,它以其它文件少有的方式顯示了世界上書寫語言的豐富性和多樣性。此外,該書還提供了開發Unicode的基本原理和細節。Unicode有缺點嗎?固然有。Unicode字符串佔用的內存是ASCII字符串的兩倍。(然而壓縮文件有助於極大地減小文件所佔的磁盤空間。)但也許最糟的缺點是:人們相對來講還不習慣使用Unicode。身爲程序寫做者,這就是咱們的工做。寬字符和 C對C程序寫做者來講,16位字符的想法的確讓人掃興。一個char和一個字節同寬是最不能肯定的事情之一。沒幾個程序寫做者清楚ANSI/ISO 9899-1990,這是「美國國家標準程序設計語言-C」(也稱做「ANSI C」)經過一個稱做「寬字符」的概念來支持用多個字節表明一字符的字符集。這些寬字符與經常使用的字符完美地共存。ANSI C也支持多字節字符集,例如中文、日文和韓文版本Windows支持的字符集。然而,這些多字節字符集被當成單字節構成的字符串看待,只不過其中一些字符改變了後續字符的含義而已。多字節字符集主要影響C語言程序執行時期連接庫函數。相比之下,寬字符比正常字符寬,並且會引發一些編譯問題。寬字符不須要是Unicode。Unicode是一種可能的寬字符集。然而,由於本書的焦點是Windows而不是C執行的理論,因此我將把寬字符和Unicode做爲同義語。Char數據型態假定咱們都很是熟悉在C程序中使用char數據型態來定義和儲存字符跟字符串。但爲了便於理解C如何處理寬字符,讓咱們先回顧一下可能在Win32程序中出現的標準字符定義。下面的語句定義並初始化了一個只包含一個字符的變量:char c = 'A' ; 變量c須要1個字節來保存,並將用十六進制數0x41初始化,這是字母A的ASCII代碼。您能夠像這樣定義一個指向字符串的指針:char * p ; 由於Windows是一個32位操做系統,因此指針變量p須要用4個字節保存。您還可初始化一個指向字符串的指針:char * p = "Hello!" ; 像前面同樣,變量p也須要用4個字節保存。該字符串保存在靜態內存中並佔用7個字節-6個字節保存字符串,另1個字節保存終止符號0。您還能夠像這樣定義字符數組:char a[10] ; 在這種狀況下,編譯器爲該數組保留了10個字節的儲存空間。表達式sizeof(a)將返回10。若是數組是總體變量(即在全部函數外定義),您可以使用像下面的語句來初始化一個字符數組:char a[] = "Hello!" ; 若是您將該數組定義爲一個函數的區域變量,則必須將它定義爲一個static變量,以下:static char a[] = "Hello!" ; 不管哪一種狀況,字符串都儲存在靜態程序內存中,並在末尾添加0,這樣就須要7個字節的儲存空間。寬字符Unicode或者寬字符都沒有改變char數據型態在C中的含義。char繼續表示1個字節的儲存空間,sizeof (char)繼續返回1。理論上,C中1個字節可比8位長,但對咱們大多數人來講,1個字節(也就是1個char)是8位寬。C中的寬字符基於wchar_t數據型態,它在幾個表頭文件包括WCHAR.H中都有定義,像這樣:typedef unsigned short wchar_t ; 所以,wchar_t數據型態與無符號短整數型態相同,都是16位寬。要定義包含一個寬字符的變量,可以使用下面的語句:wchar_t c = 'A' ; 變量c是一個雙字節值0x0041,是Unicode表示的字母A。(然而,由於Intel微處理器從最小的字節開始儲存多字節數值,該字節其實是以0x4一、0x00的順序保存在內存中。若是檢查Unicode文字的計算機儲存應注意這一點。)您還可定義指向寬字符串的指針:wchar_t * p = L"Hello!" ; 注意緊接在第一個引號前面的大寫字母L(表明「long」)。這將告訴編譯器該字符串按寬字符保存-即每一個字符佔用2個字節。一般,指針變量p要佔用4個字節,而字符串變量須要14個字節-每一個字符須要2個字節,末尾的0還須要2個字節。一樣,您還能夠用下面的語句定義寬字符數組:static wchar_t a[] = L"Hello!" ; 該字符串也須要14個字節的儲存空間,sizeof (a) 將返回14。索引數組a可獲得單獨的字符。a[1] 的值是寬字符「e」,或者0x0065。雖然看上去更像一個印刷符號,但第一個引號前面的L很是重要,而且在兩個符號之間必須沒有空格。只有帶有L,編譯器才知道您須要將字符串存爲每一個字符2字節。稍後,當咱們看到使用寬字符串而不是變量定義時,您還會遇到第一個引號前面的L。幸運的是,若是忘記了包含L,C編譯器一般會給提出警告或錯誤信息。您還可在單個字符文字前面使用L前綴,來表示它們應解釋爲寬字符。以下所示:wchar_t c = L'A' ; 但一般這是沒必要要的,C編譯器會對該字符進行擴充,使它成爲寬字符。