WisdomSoft - for your serial experiences.

2.10 型変換

異なる型の値を組み合わせた計算や代入がどのように行われるのか解説します。小さな型をより大きな型に変換する場合は失われる情報が無いため安全ですが、大きな型をより小さな型に変換する場合、情報が削られる可能性があります。

2.10.1 算術変換

整数型と浮動小数点型を算術演算することを想像してください。式の中に異なるデータ型の値が組み合わされた時は、どのようになるのでしょう。

7 + 3.14

整数と浮動小数点数は型が異なるため、このような算術演算を行うには項の型を一致させなければなりません。すなわち、整数型を浮動小数点型に変換して 7.0 + 3.14 と解釈するか、浮動小数点型を整数型に変換して 7 + 3 とするかです。このように、ある値を別の型に移行させることを変換(conversions)と呼びます。変換には、型や変換方法によっていくつか種類があります。

上の式のように型の異なる値を 2 項演算子で計算しようとした場合、演算子によって自動的に項の型変換が行われます。このような変換を算術変換(arithmetic conversions)と呼びます。算術変換には明確な法則があり、項の型の組み合わせによって変換方法が決定します。基本的には、より表現力の高い型に変換されると考えてください。

例えば、同じ整数型の計算でも char 型と int 型の変数が組み合わせられた場合、小さい型である char 型の項が int 型に変換されてから計算されます。より小さい型の値を、より大きい型に変換してもデータが失われることはないため、このような型の昇格が行われます。小さな整数型の値が、より大きな型に変換される仕組みを整数の昇格(integral promotions)と呼びます。

コード1
#include <iostream>

int main()
{
	char c = 100;
	int i = 1000;
	int k = i + c;
	
	std::cout << k << "\n";
	return 0;
}
実行結果
コード1 実行結果

コード1は char 型の c 変数と int 型の i 変数を加算し、その結果を k に格納しています。このとき、型の異なる c 変数と i 変数を加算演算子で計算していますが、算術変換によって c 変数を指定した項が int 型に昇格しています。加算演算の結果は int 型なので、int 型の変数 k に代入できます。実行結果からも、計算が正しく行われたことが確認できます。

整数の昇格と同じ法則が浮動小数点型でも働きます。より小さい float 型から double 型への変換は、データに変更を加えることなく安全に移行できます。より小さな浮動小数点型の値が、より大きな型に変換される仕組みを浮動小数点の昇格(floating point promotion)と呼びます。

コード2
#include <iostream>

int main()
{
	float f = 1.4142;
	double d = 3.1415;
	double e = f + d;
	
	std::cout << e << "\n";
	return 0;
}
実行結果
コード2 実行結果

コード2は float 型の f 変数と double 型の d 変数を加算し、結果を double 型の e 変数に代入しています。整数と同様に f + d の計算を行うとき、float 型の f 変数を指定した項が double 型に昇格します。よって、この加算演算の結果は double 型となります。

整数と浮動小数点数の組み合わせでは、算術変換によって整数が浮動小数点型に変換されてから計算されます。従って、演算の結果は浮動小数点数型になります。

コード3
#include <iostream>

int main()
{
	std::cout << 3.14 + 10 << "\n";
	return 0;
}
実行結果
コード3 実行結果

コード3は単純に 3.14 + 10 を計算した結果を出力するプログラムです。実行結果を見れば、この加算演算の結果が浮動小数点型であることが確認できます。算術変換では、一方の項が浮動小数点型であれば他方の項を浮動小数点型に変換します。

2.10.2 明示的な型変換

算術変換による整数の昇格のように、プログラミング言語の規定により自動的に発生する変換を暗黙の型変換(implicit conversion)と呼びます。これに対し、明示的に型変換するコードを記述することもできます。このような、コードによって指示された変換を明示的な型変換(explicit conversion)と呼びます。

int 型の値を char 型に変換すると上位ビットが消失してしまうため、データを失う可能性があります。浮動小数点型から整数型に変換しようとした場合も、少数が切り捨てられてしまいます。このようなデータを失う可能性がある変換を行うと、ビルド時に警告が発生します。

コード4
#include <iostream>

int main()
{
	double d = 3.14;
	int i = d;
	
	std::cout << i << "\n";
	return 0;
}
実行結果
コード4 実行結果

上記のコードは、double 型の d 変数を int 型の i 変数に代入しています。このとき d 変数の値 3.14 が整数型に変換され、少数が切り捨てられて 3 が代入されます。

同じ整数型であっても、大きな整数型から小さな整数型に変換するとき、表現可能な最大値が縮小するため一部のデータが失われる可能性があります。例えば int 型から short 型や char 型に変換すると、上位ビットが消失します。

このような型の縮小変換が意図したものであることを明記するにはキャスト演算子(cast expression)を使います。キャスト演算子によって、明示的に型を指定できます。

キャスト演算子
(型)式

キャスト演算子は、式に指定した値の結果を丸括弧内の型に変換します。コード4のような double 型から int 型への縮小変換もキャスト演算子による明示的な型変換にすることで警告が発生しなくなります。

double d = 3.14;
int i = (int)d;

型の大小だけではなく、型の種類を変更するためにもキャスト演算が有効です。例えば、文字を数値として扱ったり、その逆を行ったりする場合です。通常 std::cout へ char 型の値を出力すると 1 文字として解釈されますが、文字ではなく値として表示したい場合は char 型の値を int 型に変換します。 

コード5
#include <iostream>

int main()
{
	char c = 'A';
	
	std::cout << c << "\n";
	std::cout << (int)c << "\n";
	return 0;
}
実行結果
コード5 実行結果

コード5は char 型の c 変数に文字リテラル 'A' を代入しています。この c 変数を std::cout へ出力すると、char 型のデータなので c 変数に保存されている文字が表示されます。しかし char 型の文字も 1 バイトのデータにすぎません。これをキャスト演算子で int 型に変換すれば、文字 'A' に対応する文字コード 65 が出力されます。