Cpp 文字列リテラル

提供:yonewiki
2024年1月30日 (火) 00:04時点におけるYo-net (トーク | 投稿記録)による版 (→‎string_view リテラル " "sv)

C++に戻る


本来の表記は「C++(Cpp) 文字列リテラル」です。この記事に付けられた題名はテンプレート:記事名の制約から不正確なものとなっています。

※このページではC++にのみ存在する機能として、記事タイトルがC++ 文字列リテラルになっています。

文字列リテラル

 文字列リテラルのリテラル(Literal)とは英語で文字通りのという意味があります。プログラムでは文字列そのものを表す表現という意味でもあり、初期化や関数の引数で文字列を指定するときの表現となっています。C++ではダブルクォーテーションで囲うものが有名です。


通常リテラル " "

"abc"


 はいはい。見たことあります。こういう表記ですね。みたことない?。そっかそっか。まだまだ知らない人もいるんだね。文字列を引数にとる関数を呼び出すときは、以下のようにも表記できるってことです。


function("abc");


 おー。ダブルクォーテーションの使い方。これこれ。これを見たかったね。


 ここからがこの記事の本番です。ダブルクォーテーションで囲うのなんて、みんな知ってるっつうのね。プログラムやったことある人ならね。このリテラルっていうものには、たくさんの種類が準備されているのが、C++なのです。それをここで全部知っていこうとする記事です。リテラル。深い!

wchar_t リテラル L" "

 まずは、wchar_t型の引数の場合はこうですね。Unicodeの範囲が使えるよね。


function(L"日本語もハングル한국어もいけるニダっし、そのほかの謎の国際言語Киргиз тилиってね。");


 このようにL""とするだけで使えます。


char wchar_t スイッチ リテラル _T(" ")

 そしてマイクロソフトが考えた_TでUnicodeを使うプロジェクトの場合はL""と同じで、そうでないプロジェクトに対しては""で扱うみたいな方法があって


function(_T("Hello, World!"));


という記法です。これは以下の設定に従います。


Character Set (文字セット):

プロジェクトのプロパティを開きます。 「構成プロパティ」 -> 「詳細設定」 -> 「文字セット」 「文字セット」が「Unicode 文字セットを使用する」の場合、_T マクロはワイド文字列 (wchar_t型) に展開されます。


Preprocessor Definitions (プリプロセッサの定義):

_UNICODE マクロが定義されていることを確認します。 プロジェクトのプロパティ -> 「構成プロパティ」 -> 「C/C++」 -> 「プリプロセッサ」 -> 「前処理済みのディフェクト」 _UNICODE が含まれていることを確認します。


 これらの設定によって、_T マクロは _UNICODE マクロの定義状態に基づいて、適切な文字列型に展開されます。


 ね。いろいろあるでしょ。でも、ここまではまだ基本です。プログラマなら知っておいてよっていうレベルね。


 まだまだあります。さきにいろいろな説明を省略してどんなものがあるかをずらっと並べます。


char8_t  utf8   = u8'a' ;
char16_t utf16  = u'あ' ;
char32_t utf32  = U'あ' ;

function(R"(a
b
c)");

function(LR"(

)");

// string
auto str    = "Hello, World!"s ;
// u8string
auto u8str  = u8"こんにちは世界! Hello, World!"s ;
// u16string
auto u16str = u"こんにちは世界! Hello, World!"s ;
// u32string
auto u32str = U"こんにちは世界! Hello, World!"s ;
// wstring
auto wstr   = L"こんにちは世界! Hello, World!"s ;

// string_view
auto str    = "Hello, World!"sv ;
// u8string_view
auto u8str  = u8"こんにちは世界! Hello, World!"sv ;
// u16string_view
auto u16str = u"こんにちは世界! Hello, World!"sv ;
// u32string_view
auto u32str = U"こんにちは世界! Hello, World!"sv ;
// wstring_view
auto wstr   = L"こんにちは世界! Hello, World!"sv ;


 ね。結構あるでしょ。知らないリテラルあった!って人は衝撃だよね。そう、標準でも知っておかないといけないリテラルは多いんです。これから少しづつ紹介します。


char8_t, char16_t, char32_t リテラル u8" ", u" ", U" "

 同じUnicodeでもUTF-8、UTF-16、UTF-32の3種類のエンコードを使い分けることが出来ます。


    char8_t  utf8   = u8'あ' ;//UTF-8エンコードで0xE3 0x81 0x82。
    char16_t utf16  = u'あ' ;//UTF-16エンコードで0x30 0x42
    char32_t utf32  = U'あ' ;//UTF-32エンコードで0x00 0x00 0x30 0x42

    
    //////// UTF-8のコードポイントを取得する処理 //////////////////
    uint32_t utf8Code = 0;
    int numBytes = 0;

    // 初めのバイトから先頭ビットが1の数を数える
    while ((utf8 & (0x80 >> numBytes)) != 0) {
        numBytes++;
    }

    // 先頭バイトの情報を使ってコードポイントを取得
    utf8Code = utf8 & (0xFF >> numBytes);

    // 残りのバイトを処理
    for (int i = 1; i < numBytes; i++) {
        char8_t followByte = /* 残りのバイトを取得する処理 */;
        utf8Code = (utf8Code << 6) | (followByte & 0x3F);
    }

    std::cout << "UTF-8 Code: 0x" << std::hex << utf8Code << std::endl;


    //////// UTF-16のコードポイントを取得する処理 //////////////////
    uint32_t utf16Code = static_cast<uint32_t>(utf16);
    
    std::cout << "UTF-16 Code: 0x" << std::hex << utf16Code << std::endl;

    //////// UTF-32のコードポイントを取得する処理 //////////////////
    uint32_t utf32Code = static_cast<uint32_t>(utf32);
    
    std::cout << "UTF-32 Code: 0x" << std::hex << utf32Code << std::endl;


 この先もUnicodeのそれぞれのエンコードについて表現しますが、以降は、コードポイントがどうやって確認できるかという議論は省略します。


生文字列リテラル R"( )", LR"( )"

 生文字列リテラルを指定すると改行文字も反映したリテラルというものが作れます。


const char* multilineChars = R"(a
b
c)";

const char* multilineWideChars = LR"(あい
こころ
おもい)";


 multilineCharsはa\nb\ncで初期化されたのと同じことになります。LRとするとwchar_t型の初期化として使えます。


 改行文字が反映できるだけでなく、全てエスケープシーケンスを無効化できる効果、連続した空白の保持といった効果も得られるのが生文字列リテラルの特徴です。


string リテラル " "s

 string形式の初期化に使えるリテラルが " "s です。サンプルでは型推論で使いましたが、関数の引数がstringになっているときに明示して使うこともできます。


auto stringStr = "Hello, World"s;


wstring リテラル L" "s

 日本語文字を使えるようにする wstring に対応するには L" "s を使います。まぁ日本語だけじゃないんですけどね。

auto wstringStr = L"こんにちは!世界!Hello, World"s;


u8string リテラル u8" "s

 日本語文字を使えるようにしつつUTF-8エンコードを使う u8string に対応するには u8" "s を使います。

auto utf8stringStr = u8"こんにちは!世界!Hello, World"s;


u16string リテラル u" "s

 日本語文字を使えるようにしつつUTF-16エンコードを使う u16string に対応するには u" "s を使います。

auto utf16stringStr = u"こんにちは!世界!Hello, World"s;


u32string リテラル U" "s

 日本語文字を使えるようにしつつUTF-32エンコードを使う u32string に対応するには U" "s を使います。

auto utf32stringStr = U"こんにちは!世界!Hello, World"s;


string_view リテラル " "sv

 string_view形式の初期化に使えるリテラルが " "sv です。string_viewって何?って感じですが、文字列を非所有とした型です。つまり実体は別のところにある状態です。つまり、参照してるだけです。そしたらもう一個、string型の値がいるから非効率ですが、もうふたつ特徴があります。それは、参照してるだけだから本体を書き換えないですむという保護機能。もうひとつは、右辺値を参照することで、メモリの節約になるという機能です。但し右辺値を使った場合、名前空間のスコープから出ていくと参照できなくなるので、同じスコープ内でしか有効でないことに注意が必要です。


 いま説明したことを簡単なサンプルで指し示すと、

const char* str = "Hello, World!";
std::string_view view(str, strlen(str)); //viewという変数を初期化

std::string_view view = "Hello, World!";  // リテラルから作成。右辺値参照


 となります。


 stringのリテラル説明と同じくサンプルでは型推論で使いましたが、関数の引数がstringになっているときに明示して使うこともできます。全て、リテラルの末尾sをsvにするだけです。


auto string_viewStr = "Hello, World"sv;


wstring_view リテラル L" "sv

 日本語文字を使えるようにする wstring_view に対応するには L" "sv を使います。まぁ日本語だけじゃないんですけどね。

auto wstring_viewStr = L"こんにちは!世界!Hello, World"sv;


u8string_view リテラル u8" "sv

 日本語文字を使えるようにしつつUTF-8エンコードを使う u8string_view に対応するには u8" "sv を使います。

auto utf8string_viewStr = u8"こんにちは!世界!Hello, World"sv;


u16string_view リテラル u" "sv

 日本語文字を使えるようにしつつUTF-16エンコードを使う u16string に対応するには u" "sv を使います。

auto utf16string_viewStr = u"こんにちは!世界!Hello, World"sv;


u32string_view リテラル U" "sv

 日本語文字を使えるようにしつつUTF-32エンコードを使う u32string_view に対応するには U" "sv を使います。

auto utf32string_viewStr = U"こんにちは!世界!Hello, World"sv;


 

C++に戻る