C言語で暗黙的に行われる型変換についてまとめます。初回は汎整数拡張です。
汎整数拡張とは
C90の記述を確認します。
int型又はunsigned int型を使用してもよい式中ではどこでも,char,short int,int ビットフィールド,それらの符号付き版若しくは符号無し版,又は列挙型をもつオブジェクトを使用してもよい。いずれの場合でも,int型が元の型のすべての値を表現できるならば値をintに型変換し,それ以外はunsigned intに型変換する。この操作は,汎整数拡張(integer promotion)と呼ぶ。
JIS X 3010:1993 6.2.1.1
C99では、記述に以下の差はありますが、本質的には変わりません。
- 変換前の型に_Bool型が加わる。
- 単に「整数拡張」と呼ぶようになった。
汎整数拡張は、簡単に言えば、intより小さいまたは同等の大きさの整数は、int型に暗黙的に型変換して使います、ということです。
この汎整数拡張は、整数の型変換としては他の型変換より前に行われます。多くのひとは意識しないかもしれません。
実際の例
int型を32ビットとします。char型は8ビットだとします。以下のコード片はどう動くでしょうか。
unsigned char a = 255;
unsigned char b = 255;
int c;
c = a + b;
実はオーバーフローすることなくうまく動きます。汎整数拡張で行われていることをキャストによって明示すると以下になります。
unsigned char a = 255;
unsigned char b = 255;
int c;
c = (int)a + (int)b;
組込みシステムの場合、プログラムはROM(フラッシュメモリであることがほとんどです)に、変数はRAMに格納されます。
メモリリソースが乏しいマイコンでは、RAM使用量を削減するために、なるべく小さい整数型を用いる場合があるようです。ただし、この場合は、汎整数拡張の処理が発生するため、ROM(プログラム)の使用量が増えることがあります。
次の例をみてください。
unsigned char a = 255;
unsigned char b = 255;
unsigned char c;
c = a + b;
汎整数拡張と代入で行われる暗黙の型変換をキャストで示すと以下となります。
unsigned char a = 255;
unsigned char b = 255;
unsigned char c;
c = (unsignd char)((int)a + (int)b);
ただし、コンパイラがこの暗黙の型変換を行わなくても、(オーバーフローが発生したとしても)正しい結果を得られるのであれば、この汎整数拡張を省くことができます。これは、規格が言語処理系に最適化を行うことを認めているためです。
最後に
C言語が行う暗黙の型変換について、いくつかの記事でまとめてみます。
C言語を使いこなしていきましょう!