2.11 型変換
2.11.1 算術変換
これまでも、計算式を何度も使ってきましたが、実際のプログラミングでは演算式のオペランドに、変数を用いることが多々あることでしょう。しかし、それらの変数が必ずしも同じ型であるとは限りません。たとえば計算式の演算で int 型と float 型の演算が行なわれた場合はどうなるでしょう?C言語では、このような異なる型の演算を行っても文法的には間違いではありません。
オペランドは、式の中でよりサイズの大きい型に合わせて変換されるというお約束があります。もし、サイズの大きい型を小さい型に変換した場合、上位ビットを切り捨てることになるため、情報を失ってしまう可能性があります。しかし、サイズを拡張する場合は情報を失うことはありません。また、int 型以下のサイズの型は、式において int 型(すなわち、マシン演算で使う整数サイズ)に変換されます。これは普段、プログラマが意識する必要はありませんが、知っておいて損はないでしょう。
このような演算式における変換を算術変換と呼びます。変換規則をまとめると、表1のようになります。
#include <stdio.h> int main() { char chVar = 50; int iVar = 100; float fVar = .555; printf("%g\n" , chVar + iVar + fVar); return 0; }
このプログラムでは、printf() 関数の引数部で chVar + iVar + fVar という演算を行っていますが、これらの変数は、全てが異なる型です。そこで、算術変換が採用され、最終的には最も大きいサイズである float 型に変換されます。char 型や int 型の値は float 型に変換されても失う情報はありません。最終的には 150.555 という結果が得られるでしょう。
2.11.2 代入変換
式において、異なる型のオペランドが存在する場合は算術変換が行われましたが、評価の結果を代入する変数が演算結果の型と同一であるとは限りません。
代入の場合も、型が異なる場合は暗黙的に変換して代入されます。これを代入変換と呼びます。このとき変数のサイズが式の型より大きい場合は何の問題もありません。評価の結果型よりも大きなサイズに変換しても、失われる情報はないからです。
#include <stdio.h> int main() { char chVar = 100; int iVar = chVar; printf("iVar = %d\n" , iVar); return 0; }
コード2は、char 型変数を int 型変数に代入しています。この場合、char 型変数 chVar の値が int 型に拡張されることになります。元のサイズよりも拡張される変換の場合は、失う情報はないので問題はありません。
しかし、逆に左辺の変数型が右辺の評価よりもサイズが小さい時は問題があります。この場合でもエラーは発生しませんが、値は情報の一部を損失して代入されます。例えば int から char に変換された場合は上位ビットが切り捨てられて代入されます。
#include <stdio.h> int main() { int iVar = 0xABCD; unsigned char chVar = iVar; printf("chVar = %X\n" , chVar); return 0; }
コード3では、int 型変数 iVar を char 型変数 chVar に代入しています。この場合、型が異なるため代入変換が適用されますが、int 型から char 型への変換では問題が発生します。char 型は int 型よりもサイズが小さいため、この場合は縮小変換されてしまうのです。そのため、8 ビット以上の上位バイトは切り捨てられてしまうため、その結果一部の情報を失うことになります。
int 型が32ビットであると仮定した場合、iVar の値は2進数で 0000 0000 0000 0000 1010 1011 1100 1101 となります。これを 8 ビットである char 型に変換した場合、上位ビットが切り捨てられ 1100 1101 となります。その結果、このプログラムは16進数 CD を表示するでしょう。もし、浮動小数点型から整数型への変換が行われた場合は、小数部の情報が失われます。
「情報を失う」と表現してしまえば、何もかもが悪いことのように感じられますが、下位8ビットを取り出したい場合や、浮動小数点型の整数部だけを抽出したい場合には、このような縮小変換が役に立ちます。場合に応じてうまく利用できるようになりましょう。
2.11.3 型キャスト変換
これまでの算術変換や代入変換は、暗黙的な型変換でした。しかし、指定した型に値を変換するようにプログラマが伝える明示的な変換方法も存在します。これを型キャスト変換と呼びます。C 言語では何らかの型を、異なる型に強制的に変換することができるのです。型キャスト変換を利用するには、次のような構文を用います。
(変換型名)式
型を変換型名で指定し、その型に変換する式を指定します。式の評価結果は指定した型に変換され、代入先や関数の引数として渡されます。
#include <stdio.h> int main() { float fVar = 12.34f; printf("全体 = %g\n" , fVar); printf("実数 = %d\n" , (int)fVar); printf("小数 = %g\n" , fVar - (int)fVar); return 0; }
コード4は、型キャストを利用して浮動小数点型変数 fVar から実数や少数を取り出しています。このように、キャストを用いればより小さい型に変換することもできるため、上位ビットを切り捨てたり、小数点型を整数型に変換するということが可能になります。