最終更新日時(UTC):
が更新

履歴 編集

char16_tとchar32_t(C++11)

概要

char16_tはUTF-16符号化形式の文字型、char32_tはUTF-32符号化形式の文字型である。

UTF-16とUTF-32は、ISO/IEC 10646で標準化されている文字コード「UCS (Universal Coded Character Set)」とその互換文字コードである「Unicode (ユニコード)」で定義されている符号化形式である。UTF-16は、ひとつのコードポイント(≒文字)を表すために16ビットを基本的に使用する。UTF-32は32ビットである。

標準C++では、これらの文字符号化形式を表す文字型、そのリテラル、および文字コード・符号化形式を変換する機能を提供する。

// UTF-16/UTF-32符号化形式の文字列。
// uプレフィックスを付けた文字列リテラルはchar16_tのシーケンスとなる。
// Uプレフィックスを付けた文字列リテラルはchar32_tのシーケンスとなる。
char16_t s16[] = u"あいうえお";
char32_t s32[] = U"あいうえお";

// 文字列中にユニバーサルキャラクタ名を直接入力できる。
// \uからはじめて4桁、もしくは\Uからはじめて8桁がユニバーサルキャラクタ名として扱われる。
char16_t s[] = u"\U00020BB7野家"; // 𠮷野家

ただし、C++11時点で、標準ライブラリではchar16_tchar32_tの入出力はサポートしない。そのため、それらの文字・文字列はシステムの文字コードに変換して入出力する必要がある。

仕様

char16_t型、char32_t型の文字・文字列リテラルと文字コード

  • char16_tchar32_tは予約語(キーワード)である。
  • uプレフィックスが付く文字リテラルの型はchar16_tであり、uプレフィックスが付く文字列リテラルの要素型はchar16_tである。
    • ひとつの文字を含むchar16_tリテラルの値は、ひとつの16ビットコードポイントで表現できるISO 10646のコードポイント値と同じである。
    • ひとつの値を16ビットで表現できない場合、プログラムは不適格となる。
    • 複数の文字を含むchar16_t文字リテラルは不適格である。
    • char16_t文字リテラルが、基本文字集合とユニバーサルキャラクタ名より多くを含む場合は実装定義となる。
    • char16_tの場合、ひとつの文字がひとつ以上のchar16_tを生成することがある。その文字はサロゲートペアと呼ばれる。
    • char16_t型の文字列リテラルは、静的ストレージに配置される。
  • Uプレフィックスが付く文字リテラルの型はchar32_tであり、Uプレフィックスが付く文字列リテラルの要素型はchar32_tである。
    • ひとつの文字を含むchar32_tリテラルの値は、ひとつの32ビットコードポイントで表現できるISO 10646のコードポイント値と同じである。
    • ひとつの値を32ビットで表現できない場合、プログラムは不適格となる。
    • 複数の文字を含むchar32_t文字リテラルは不適格である。
    • char32_t文字リテラルが、基本文字集合とユニバーサルキャラクタ名より多くを含む場合は実装定義となる。
    • char32_t型の文字列リテラルは、静的ストレージに配置される。
  • char16_tchar32_tはそれぞれ、<cstdint>ヘッダで定義されるuint_least16_tuint_least32_tと、サイズ、符号の有無、アライメントが同じである。
  • <uchar>ヘッダでマクロ__STDC_UTF_16__が定義される場合、char16_t型の値はUTF-16の妥当なコードポイントを持つ。そうでない場合、char16_t型の値は実装定義の文字コードとなる。
  • <uchar>ヘッダでマクロ__STDC_UTF_32__が定義される場合、char32_t型の値はUTF-32の妥当なコードポイントを持つ。そうでない場合、char32_t型の値は実装定義の文字コードとなる。

ユニバーサルキャラクタ名

  • char16_t文字・文字列リテラルとchar32_t文字・文字列リテラルのなかには、UCS/Unicodeのユニバーサルキャラクタ名を直接記述できる。たとえば、char16_t文字リテラルu'\u215A'U+215Aコードポイントの文字である'⅚' (VULGAR FRACTION FIVE SIXTHS) を表す。\uの場合は16進数で4桁固定のユニバーサルキャラクタ名を、\Uの場合は16進数で8桁固定のユニバーサルキャラクタ名を記述する。

    #include <cassert>
    
    int main()
    {
      char16_t a = u'\u215A';
      char16_t b = u'⅚';
    
      assert(a == b);
    }
    

  • char16_tchar32_tのユニバーサルキャラクタ名は、[0x0, 0x10FFFF]の範囲内であること。

参照するUCSの規格

C++11時点の規格では、UCSの規格としてISO/IEC 10646-1:1993を参照する。

サロゲートペアを含む状況

#include <cassert>
#include <string>

int main()
{
  std::u16string s16 = u"𠮷野家";
  std::u32string s32 = U"𠮷野家";

  assert(s16.size() == 4); // サロゲートペアを含むので1文字分多い
  assert(s32.size() == 3); // UTF-32にサロゲートペアはない
}

出力

UTF-32に文字コード変換して簡易的にコードポイント数を算出する

#include <iostream>
#include <string>
#include <locale>
#include <codecvt>

int main()
{
  // UTF-8とUTF-32の相互変換を行うコンバーター
  std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> converter;

  // UTF-8からUTF-32に変換
  std::string u8str = u8"あいうえお";
  std::u32string u32str = converter.from_bytes(u8str);

  // コードポイント数を取得
  std::size_t codepoint_count = u32str.size();
  std::cout << codepoint_count << std::endl;
}

出力

5

この機能が必要になった背景・経緯

この機能が提案された2004年当時にはすでにUCS/Unicodeが広く普及していた。多くのユーザーがその文字コードを扱うことを望んでいたために、標準C++で正式にサポートすることとなった。

関連項目

参照