リテラルと型
データを直接コードに書く
プログラムの中に直接書かれた値は、何度プログラムを実行しても変化することはありません。このような固定値のことをリテラル(literal)または定数(constant)と呼びます。これまでのプログラムで表示してきた、二重引用符で括った文字列は、文字列リテラルと呼ばれるリテラルの一種です。この他にも 10 や 3.14 などの数値など、リテラルは扱うデータに応じて次のいずれかに分類できます。
- 整数リテラル
- 浮動小数点リテラル
- ブーリアンリテラル
- 文字リテラル
- 文字列リテラル
このようにリテラルが分類されているのは、データの種類によって表現方法や操作方法が異なるためです。例えば、文字列と数値は互いに計算できないということは容易に想像できると思います。これらのリテラルは、互いにデータとしての表現方法が大きく異なっています。このような、データの表現方法や操作方法の違いに応じて扱いを区別するために型 (Type)という概念が用いられます。文字列と数値は型が異なるのです。
上記のリテラルの種類は、リテラルが表現するデータ型ごとに分類されています。整数リテラルは整数型のデータを記述するための記法であり、文字列リテラルは文字列型のデータを記述するための記法です。
整数リテラル
整数リテラル(integer literal)は、小数点以下を含まない整数をコード内で表します。これは、私たちが普段日常で使っている数と同じだと思ってかまいません。つまり、コード内に書かれている 10 や 1234 といった値は整数リテラルであると解釈できます。
このとき、数字を二重引用符 " で囲まないでください。二重引用符に囲まれている部分は文字列リテラルとして解釈されます。整数リテラルは数値として扱われ、文字列リテラルは文字の並びとして扱われます。リテラルとして表記された 1234 は整数リテラル、"1234" は文字列リテラルとして処理されるのです。数値と文字列は型が異なるため、保存方法や値の操作方法も、それぞれ異なります。
これまで二重引用符で囲った文字列を出力してきたように、他のリテラルも同じ方法で std::cout へ出力できます。
#include <iostream> int main() { std::cout << 10 << "\n"; std::cout << 1943 << "\n"; return 0; }
コード1は整数リテラルを出力した例です。コード上に書かれている整数値が、そのまま結果として表示されています。
0 以外の数字で始まる整数リテラルは 10 進数と解釈されますが、それ以外に 8 進数と 16 進数で整数を表すこともできます。コンピュータの内部では、あらゆるデータが 2 進数で保存されているため、プログラムが扱うデータによっては 8 進数や 16 進数で記述した方が便利になることがあります。
8 進数の整数リテラルは 0 から始まり 0 ~ 7 までの数字の組み合わせで表します。8 進数リテラルで使える数字は 0 ~ 7 の範囲だけなので 07 の次は桁を増やして 010 (10進数における 8)になります。
16 進数の整数リテラルは 0x から始まり 0 ~ 9 までの数字と A ~ F までのアルファベット、または a ~ f までのアルファベットで表せます。16 進数では 9 以降の値を A ~ F までのアルファベットで表すことができるため 0xF (10 進数における 15)の次で桁が増えて 0x10 となります。アルファベットの大文字と小文字の組み合わせは自由ですが、通常はどちらか一方に統一します。
2進数 | 8進数 | 10進数 | 16進数 |
---|---|---|---|
0000 0001 | 01 | 1 | 0x1 |
0000 0010 | 02 | 2 | 0x2 |
0000 0011 | 03 | 3 | 0x3 |
0000 0100 | 04 | 4 | 0x4 |
0000 0101 | 05 | 5 | 0x5 |
0000 0110 | 06 | 6 | 0x6 |
0000 0111 | 07 | 7 | 0x7 |
0000 1000 | 010 | 8 | 0x8 |
0000 1001 | 011 | 9 | 0x9 |
0000 1010 | 012 | 10 | 0xA |
0000 1011 | 013 | 11 | 0xB |
0000 1100 | 014 | 12 | 0xC |
0000 1101 | 015 | 13 | 0xD |
0000 1110 | 016 | 14 | 0xE |
0000 1111 | 017 | 15 | 0xF |
0001 0000 | 020 | 16 | 0x10 |
8 進数の 1 桁は 2 進数の 3 桁に対応し、16 進数の 1 桁は 2 進数の 4 桁 に対応していることが表1から確認できます。多くの場合、コンピュータの内部で管理されている 2 進数のデータは 4 桁または 8 桁単位で操作することになるため、特に 16 進数による表記は重要です。
#include <iostream> int main() { std::cout << "10=" << 10 << "\n"; std::cout << "010=" << 010 << "\n"; std::cout << "0x10=" << 0x10 << "\n"; return 0; }
コード2は 10 進数で表記された整数リテラル 10 と、8 進数で表記された整数リテラル 010、16 進数で表記された 0x10 を出力しています。結果はすべて 10 進数で表示されます。10 は見たまま 10 と出力されますが、8 進数 010 は 8、16 進数 0x10 は 16 と表示されています。
定数で表現できる最大範囲は C++ 言語の仕様では定められていないため処理系に依存します。
浮動小数点リテラル
整数部と少数部から構成される実数は浮動小数点リテラル(floating literal)として表記できます。浮動小数点リテラルの記法は、一般的な実数の書き方と同じで、数字列からなる整数部と小数部をピリオド . で区切ります。浮動小数点リテラルには、整数リテラルで使われていた 8 進数 16 進数はつかえません。
3.141592
上記は整数部が 3、小数部が 141592 からなる浮動小数点リテラルです。上記のような整数部と小数部で構成されたピリオドで区切られた数字列の組み合わせを小数点定数(fractional constant)とも呼びます。整数部または小数部のいずれかを省略することができ、省略された場合は 0 と解釈されます。
.123 //0.123 123. //123.0
よって 0.123 と .123 は同じ値です。
#include <iostream> int main() { std::cout << 3.1415 << "\n"; std::cout << .1415 << "\n"; std::cout << 3. << "\n"; return 0; }
浮動小数点リテラルは指数部(exponent part)を持つことができます。指数部は小数点定数または数字列の後にアルファベットの e または E に続けて指数を記述します。指数部を持つリテラルを記述することで、基数 10 の累乗の値を表現できます。
1.234e2 //123.4 123e3 //123000 .01234e4 //123.4
指数部には + または - 記号を数字列の前に置いて符号を指定できます。符号を書かなかった場合は正の数と解釈されるため、正数を表す + 記号を記述した場合と同義です。一方、指数部が負数であることを表すには - 記号による符号を明記しなければなりません。
12.34e+1 //123.4 12.34e-1 //1.234
これらの指数表記を用いることで、大きな値や小さな値を少ない桁で表すことができます。
#include <iostream> int main() { std::cout << "1.234e2=" << 1.234e2 << "\n"; std::cout << "123e2=" << 123e2 << "\n"; std::cout << ".01234e2=" << .01234e4 << '\n'; std::cout << "12.34e+1=" << 12.34e+1 << "\n"; std::cout << "12.34e-1=" << 12.34e-1 << "\n"; return 0; }
コード4は指数部を持つ浮動小数点リテラルを出力しています。例えば、指数表記を用いた浮動小数点リテラル 1.234e2 の出力結果から、これは 1.234 × 102 に等しいことが確認できます。
ブーリアンリテラル
ブーリアンリテラル(boolean literal)は、2 種類の状態のみを取ることができる特殊な値です。このリテラルが表わすブーリアンと呼ばれるデータ型は「はい、いいえ」や「ON・OFF」のような 2 通りの状態を表現するときに適しています。
ブーリアンリテラルは数字ではなく、言語仕様で定められている true キーワードまたは false キーワードのいずれかで表されます。true は「真」、false は「偽」とも呼ばれ、true は条件が満たされている状態を表し、false は満たされていない状態を表すために用いられます。この値は true と false というキーワードによって表されますが、実質的に true は整数の 1 と、false は 0 と同義です。
#include <iostream> int main() { std::cout << "true=" << true << "\n"; std::cout << "false=" << false << "\n"; return 0; }
true または false のようなブーリアン型は、異なる 2 つのデータを比較した結果などから、条件が満たされているかどうかを表すために用いられます。他にも、機能の有効化・無効化の制御や、操作対象のデータが存在するかどうかなど、2 つの状態を切り替えたり、YES または NO による返答などにも使われます。
ブーリアン型の詳細な利用方法は、後述する流れ制御でも説明します。
文字リテラル
文字リテラル(character literal)は、アルファベットや記号などの任意の 1 文字を表します。複数の文字の並びで構成される文字列と混同しないように注意してください。詳細は後述しますが、文字列は上記のような文字データが列になって並んでいる状態です。文字リテラルは引用符 ' で文字を囲みます。
'A'
当然、文字リテラルを表す引用符 ' 内に複数の文字を記入することはできません。例えば 'ABC' というような文字リテラルはエラーになります。二重引用符 " で括った文字列とは区別されるので注意してください。また、文字リテラルの途中で改行はできません。
ただし、エスケープシーケンス(escape sequence)と呼ばれる特殊な文字は複数の記号と文字の組み合わせで 1 文字と解釈されます。例えば、表示できないタブ文字や改行をエスケープシーケンスで表すことができます。エスケープシーケンスは円記号 \ から始まり、続く文字や記号で 1 文字を表現します。
エスケープ文字 | 意味 |
\a | ベル文字(アラート) |
\b | 1文字分戻る |
\f | ページ送り(クリア) |
\n | 改行 |
\r | 同じ行の先頭に戻る |
\t | 水平タブ |
\v | 垂直タブ |
\' | 引用符 |
\" | 二重引用符 |
\? | はてな ? |
\\ | 円記号(バックスラッシュ) |
\ooo | 8進定数(o は8進数の値) |
\xhhh | 16進定数(h は16進数の値) |
文字列内で二重引用符を用いたい場合や、文字リテラルで引用符を表現する場合、または \ 記号やタブ文字などを表現したい場合に表2のエスケープ文字を使います。ただし、垂直タブなど一部の文字は特定のデバイスでしか意味を成さない場合もあります。
なお、システムやフォント、言語環境によって円記号ではなくバックスラッシュで表示されることがありますが同じです。
#include <iostream> int main() { std::cout << "アルファベットA=" << 'A' << "\n"; std::cout << "ベル文字=" << '\a' << "\n"; std::cout << "円記号=" << '\\' << '\n'; std::cout << "16進定数 x61=" << '\x61' << "\n"; return 0; }
コード6は複数の文字リテラルを出力しています。文字リテラルは 1 文字を表すデータなので、通常の文字は引用符内に 1 文字(記号)しか指定できません。ただし、エスケープ文字は \ 記号と他の文字で 1 文字と解釈されます。
文字列リテラル
文字列リテラル(string literal)は、二重引用符で囲んだ任意の長さの文字列です。これまでも、コマンドプロンプト上に表示するテキストとなる文字列リテラルを何度か書いてきました。
"Stand by Ready!!"
文字列リテラルは文字リテラルと同様に、途中で改行することはできません。エスケープシーケンスを記述することで水平タブや改行などを表すことができます。
#include <iostream> int main() { std::cout << "\"Hello\"\n\tDazzling World\n"; return 0; }
コード7はエスケープシーケンスを用いて 1 つの文字列内に二重引用符や改行、水平タブなどを含めています。
隣り合う文字列リテラルは自動的に連結されます。例えば、以下のような 2 つの連続した文字列リテラル
"Dazzling " "World"
これら隣り合う文字列リテラルは、コンパイル時に 1 つの文字列リテラルとして、次のように連結されます。
"Dazzling World"
長い文章をコード内に埋め込むことは避けるべきですが、それでもプログラムの都合上や簡素化のために長文のテキストを文字列リテラルとして記述しなければならないこともあるでしょう。そのような場合は、行ごとに文字列リテラルを分割するなどすれば、多少は読みやすくなります。
#include <iostream> int main() { std::cout << "The wind is in the sky,\n" "the stars are in the heavens.\n" "And a resolute heart beats within my chest!\n" "This magic in my hand.\n"; return 0; }
コード8は長文のテキストを行ごとに区切った文字列リテラルとして記述しています。隣接する文字列リテラルはコンパイル時に連結されるため、複数の文字列リテラルは 1 つにまとめられ std::cout に出力されます。