UTF-16での注意点

ドキュメント上の "Unicode" という単語の意味に注意

特に Microsoft のドキュメントに多いのですが、文脈によって "Unicode" という単語が純粋にUnicodeを指している場合と、エンコーディングとしての UTF-16 (もしくは UCS-2)を指している場合とがありますので、混乱しないように注意が必要です。

1文字が必ずしも16ビット固定ではない

これもまた、Microsoft の古いドキュメントに多いのですが、Unicode の1文字は16ビット固定であるかのような印象を受けるドキュメントをよく目にします。ところが、現実にはそうではありません。

UTF-16 は、基本的な文字(BMP)については 16ビット固定で表現し、それ以外の文字はサロゲートペアという方法で4バイトで表現するというエンコーディングです。UCS-2 は、BMPのみを扱う16ビット固定のエンコーディングです。
Unicode はバージョン 3.1 まではBMP以外に文字を定めていなかったため、UTF-16UCS-2 はほとんど等価なものでした。
現在では、BMP 以外にも文字が追加され、それらの文字は UTF-16 においては1文字を4バイトで表現されます。UCS-2 のみをサポートすると明言した場合、すなわち扱えるデータをUCS-2に制限した場合、1文字はすべて16ビットの固定長となります。
ただし、UCS-2のみの場合でも自分で作成したアプリケーションと外側との境界においては、各文字がBMP内に納まっているかを確認するようにしましょう。入ってくるデータが正当な範囲内であるのかをチェックするのはもちろんのこと、出ていくデータ、ライブラリ関数に渡すデータにも非BMPの文字が含まれないようにするべきです。あなたのコードが「無害」と判断したデータは、それを受け取る次段では実は有害なデータであるかも知れません。

また、サロゲートされないBMPの文字だけを使っている場合でも、Unicode では文字の合成、分解が定義されており、特定の文字に対して、合成済みの文字を使って1文字で表わすこともあれば、1つの基底文字に1つ以上の結合文字を組み合わせて表現することもあります。
例えばは、合成済みの文字を使って U+304Cの単一文字で表わすこともできますし、基底文字と結合用の濁点を組み合わせて U+304B U+3099 と表わすこともできます。これはUTF-16 だけでなく、UCS-2 であっても当てはまります。

これらの理由により、1文字が16ビット固定であると思い込んだ場合、見かけ上の文字数と実際のバイト数の不一致により、思わぬところで文字列を切ってしまう、文字数に対してバッファ領域が足りない、などの問題を起こす可能性があります。

文字数とバイト数の違いに注意

ドキュメント類によって、バッファサイズなどが Unicode の文字数単位で指定されている場合と、バイト数で指定されている場合が混在しています。これらを混乱することによるバッファオーバーフローには注意が必要です。
また、複雑なエンコーディングにより、バイト数でバッファサイズを指定したときに、文字の途中で文字列が分断されることも考えられますので、その点についても注意が必要です。


(続く)