UTF-16

UTF-16描述

Unicode的编码空间从U+0000到U+10FFFF，共有1,112,064个码位（code point）可用来映射字符。Unicode的编码空间可以划分为16个平面（plane），每个平面包含2¹⁶（65,536）个码位。16个平面的码位可表示为从U+xx0000到U+xxFFFF，其中xx表示十六进制值从00₁₆到10₁₆，共计16个平面。第一个平面称为基本多语言平面（Basic Multilingual Plane, BMP），或称第零平面（Plane 0），其他平面称为辅助平面（Supplementary Planes）。基本多语言平面内，从U+D800到U+DFFF之间的码位区段是永久保留不映射到Unicode字符。UTF-16就利用保留下来的0xD800-0xDFFF区块的码位来对辅助平面的字符的码位进行编码。

从U+0000至U+D7FF以及从U+E000至U+FFFF的码位

第一个Unicode平面（码位从U+0000至U+FFFF）包含了最常用的字符。该平面被称为基本多语言平面，缩写为BMP（Basic Multilingual Plane，BMP）。UTF-16与UCS-2编码这个范围内的码位为16比特长的单个码元，数值等价于对应的码位。BMP中的这些码位是仅有的可以在UCS-2中表示的码位。

从U+D800到U+DFFF的码位

Unicode标准规定U+D800...U+DFFF的值不对应于任何字符。
但是在使用UCS-2的时代，U+D800...U+DFFF内的值被占用，用于某些字符的映射。但只要不构成代理对，许多UTF-16编码解码还是能把这些不符合Unicode标准的字符映射正确的辨识、转换成合规的码元。按照Unicode标准，这种码元序列本来应算作编码错误。

UTF-16与UCS-2的关系

UTF-16可看成是UCS-2的父集。在没有辅助平面字符（surrogate code points）前，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++语言把wchar_t 数据类型定义为16比特的unsigned short，这就与一个wchar_t 型变量对应一个宽字符、可以存储一个Unicode字符的规定相矛盾。相反，Linux平台的GCC编译器规定一个wchar_t 是4字节长度，可以存储一个UTF-32字符，宁可浪费了很大的存储空间。下例运行于Windows平台的C++程序可说明此点：
// 此源文件在Windows平台上必须保存为Unicode格式（即UTF-16小尾）// 因为包含的汉字“𪚥”，不能在简体中文版Windows默认的代码页936（即GBK）中表示// 该汉字在UTF-16小尾序中用4个字节表示// Windows操作系统能正确显示这样的在UTF-16需用4字节表示的字符// 但是Windows API不能正确处理这样的在UTF-16需用4字节表示的字符，把它判定为2个UCS-2字符#include <windows.h>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（wchar_t类型）与UTF-8（代码页CP_UTF8）之间的转码。例如：
#include <windows.h>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, &w, 1, a1, 128, NULL, NULL);
m1 = MultiByteToWideChar(CP_UTF8, 0, a2, n2, w1, 128);}