UTF-16

UTF-16是Unicode字元編碼五層次模型的第三層：字元編碼表的-{序列}-，用於資料儲存或傳遞。Unicode字元的碼位，需要1個或者2個16位長的碼元來表示，因此這是一個變長表示。UTF是"Unicode/UCS Transformation Format"的首字母縮寫，即把Unicode字元轉換為某種格式之意。UTF-16正式定義於ISO/IEC 10646-1的附錄C，而RFC2781也定義了相似的做法。UTF-16描述.Unicode的編碼空間從U+0000到U+10FFFF，共有1,112,064個碼位。基本多語言平面內，從U+D800到U+DFFF之間的碼位區段是永久保留不對映到Unicode字元。UTF-16就利用保留下來的0xD800-0xDFFF區段的碼位來對輔助平面的字元的碼位進行編碼。從U+0000至U+D7FF以及從U+E000至U+FFFF的碼位.第一個Unicode平面。UTF-16與UCS-2編碼這個範圍內的碼位為16位元長的單個碼元，數值等價於對應的碼位。BMP中的這些碼位是僅有的可以在UCS-2中表示的碼位。從U+10000到U+10FFFF的碼位.輔助平面，具體方法是：上述演算法可理解為：輔助平面中的碼位從U+10000到U+10FFFF，共計FFFFF個，即220=1,048,576個，需要20位來表示。如果用兩個16位長的整陣列成的-{序列}-來表示，第一個整數。因此，需要在基本多語言平面中保留不對應於Unicode字元的2048個碼位，就足以容納前導代理與後尾代理所需要的編碼空間。這對於基本多語言平面總計65536個碼位來說，僅佔3.125%。由於前導代理、後尾代理、BMP中的有效字元的碼位，三者互不重疊，搜尋是簡單的：一個字元編碼的一部分不可能與另一個字元編碼的不同部分相重疊。這意味著UTF-16是自同步的：可以透過僅檢查一個碼元來判定給定字元的下一個字元的起始碼元。UTF-8也有類似優點，但許多早期的編碼模式就不是這樣，必須從頭開始分析文字才能確定不同字元的碼元的邊界。由於最常有的字元都在基本多文種平面中，許多軟體處理代理對的部分往往得不到充分的測試。這導致了一些長期的bug與潛在安全漏洞，它們甚至存在於廣為流行且評價頗高的應用軟體中。從U+D800到U+DFFF的碼位.Unicode標準規定U+D800...U+DFFF的值不對應於任何字元。但是在使用UCS-2的時代，U+D800...U+DFFF內的值被佔用，用於某些字元的對映。但只要不構成代理對，許多UTF-16編碼解碼還是能把這些不符合Unicode標準的字元對映正確的辨識、轉換成合規的碼元。按照Unicode標準，這種碼元序列本來應算作編碼錯誤。範例：.以U+10437編碼為例:範例：UTF-16編碼程式.假設要將U+64321的格式，如下所示：V = 0x64321Vx = V - 0x10000= 0x54321= 0101 0100 0011 0010 0001Vh = 01 0101 0000 // Vx的高位部份的10 bitsVl = 11 0010 0001 // Vx的低位部份的10 bitsw1 = 0xD800 //結果的前16位元初始值w2 = 0xDC00 //結果的後16位元初始值w1 = w1 | Vh= 1101 1000 0000 0000| 01 0101 0000= 1101 1001 0101 0000= 0xD950w2 = w2 | Vl= 1101 1100 0000 0000| 11 0010 0001= 1101 1111 0010 0001= 0xDF21所以這個字U+64321最後正確的UTF-16編碼應該是：0xD950 0xDF21而在小尾序中最後的編碼應該是：0x50D9 0x21DF因為這個字超過U+FFFF所以無法用UCS-2的格式編碼。UTF-16比起UTF-8，好處在於大部分字元都以固定長度的位元組儲存，但UTF-16卻無法相容於ASCII編碼。UTF-16的編碼模式.UTF-16的大尾序和小尾序儲存形式都在用。一般來說，以Macintosh製作或儲存的文字使用大尾序格式，以Microsoft或Linux製作或儲存的文字使用小尾序格式。為了弄清楚UTF-16檔案的大小尾序，在UTF-16檔案的開首，都會放置一個U+FEFF字元作為Byte Order Mark，以顯示這個文字檔案是以UTF-16編碼，其中U+FEFF字元在UNICODE中代表的意義是 codice_21，顧名思義，它是個沒有寬度也沒有斷字的空白。以下的例子有四個字元：「朱」。UTF-16與UCS-2的關係.UTF-16可看成是UCS-2的父集。在沒有輔助平面字元前，UTF-16與UCS-2所指的是同一的意思。但當引入輔助平面字元後，就稱為UTF-16了。現在若有軟體聲稱自己支援UCS-2編碼，那其實是暗指它不能支援在UTF-16中超過2位元組的字集。對於小於0x10000的UCS碼，UTF-16編碼就等於UCS碼。Microsoft Windows作業系統核心對Unicode的支援.Windows作業系統核心中的字元表示為UTF-16小尾序，可以正確處理、顯示以4位元組儲存的字元。但是Windows API實際上僅能正確處理UCS-2字元，即僅以2位元組儲存的，碼位小於U+FFFF的Unicode字元。其根源是Microsoft C++語言把 codice_22 資料型別定義為16位元的unsigned short，這就與一個 codice_22 型變數對應一個寬字元、可以儲存一個Unicode字元的規定相矛盾。相反，Linux平臺的GCC編譯器規定一個 codice_22 是4位元組長度，可以儲存一個UTF-32字元，寧可浪費了很大的儲存空間。下例運行於Windows平臺的C++程式可說明此點：// 此原始檔在Windows平臺上必須儲存為Unicode格式// 因為包含的漢字“𪚥”，不能在簡體中文版Windows預設的內碼表936中表示// 該漢字在UTF-16小尾序中用4個位元組表示// Windows作業系統能正確顯示這樣的在UTF-16需用4位元組表示的字元// 但是Windows API不能正確處理這樣的在UTF-16需用4位元組表示的字元，把它判定為2個UCS-2字元int main()const wchar_t lwc[] = L"𪚥";MessageBoxW(NULL, lwc, lwc, MB_OK);int i = wcslen(lwc);printf("%d\n", i);int j = lstrlenW(lwc);printf("%d\n", j);return 0;Windows 9x系統的API僅支援ANSI字符集，只支援部分的UCS-2轉換。1996年釋出的Windows NT 4.0的API支援UCS-2。Windows 2000開始，Windows系統API開始支援UTF-16，並支援Surrogate Pair；但許多系統控制元件比如文字框和label等還不支援surrogate pair表示的字元，會顯示成兩個字元。Windows 7及更新的系統已經良好地支援了UTF-16，包括Surrogate Pair。Windows API支援在UTF-16LE之間的轉碼。例如：int main() {char a1[128], a2[128] = { "Hello" };wchar_t w = L'頁';int n1, n2= 5;wchar_t w1[128];int m1 = 0;n1 = WideCharToMultiByte(CP_UTF8, 0, &amp;w, 1, a1, 128, NULL, NULL);m1 = MultiByteToWideChar(CP_UTF8, 0, a2, n2, w1, 128);