第2章17 暗黙の型変換ルールを知る@イチからゲーム作りで覚えるC言語

暗黙的な型キャスト

暗黙的な型キャスト

イチからゲーム作りで覚えるC言語
連載ページ一覧へ
2章18 明示的な型変換(型キャスト)を知る
NEXT : 2章18 明示的な型変換(型キャスト)を知る
2章16 型の長さ、情報量とビットを知る : PREV

この記事でやること

前回はプロジェクト「0130_suuti_naibu」を新しく作り、char や int などの整数を扱う型について、使われているメモリサイズやビット、バイトでもてる数値の範囲についてキホンを話ししました。
今回は、新しくプロジェクト「0140_implicitconversion」を作り、暗黙の型変換についてお話します。この機能を知っていることで、C言語で計算をしたときにどのような型が内部で使われているのかを理解することができます。今回はさらっと概要のみお話しようと思います。

この記事はゆる~くC言語でコンソールゲームを作りながらプログラミングを学ぶための連載記事です。シリーズものですので記事の一覧はこちらを参照してくださいね。

型キャストを行うプログラム

型キャストを使ったソースコードをビルドして実際にプログラムを動かして結果を見てみましょう。

#include <stdio.h>
#include <limits.h>
int main() {
 unsigned char small;
 unsigned int big = 257;
 float progress = 12.3456f;
 printf( "char 型のサイズは 1 バイトで、代入できる最大値は %d \n"
                          , CHAR_MAX );
 printf( "int 型のサイズは %d バイトで、代入できる最大値は %d \n"
                          , sizeof(int), INT_MAX );
 // unsigned int から unsigned char への型キャスト
 small = (unsigned char)big;
 // 結果表示
 printf("small に収まる 1 バイトを big からキャストした結果、small は %d\n", small);
 printf("progress の実数部分は %d\n", (int)progress);
 printf("progress の小数部分は %f\n", progress - (int)progress);
}

コピペなりして、実行してみて下さい。

char 型の持てる最大値は 127 で、サイズは 1 バイト
int 型の持てる最大値は 2147483647 で、サイズは 4 バイト
char 型に収まるバイトだけとった結果 = 1
progress の実数部分は 12
progress の小数部分は 0.345600

こんな結果になりました。

暗黙の型変換とは

C言語で最初から扱えるそれぞれの整数型(char型、short型、int型、long型など)について、型が違っていても計算ができます。また、別の型への代入もすることができます。

 // char 型に short 型変数を代入し、降格が発生
 c = s;
 printf("char型変数 c には %d が代入されています。\n", c);

ここでは 1バイトのサイズしかもたない char 型の変数 c に、より 2 バイトのサイズの short 型の変数の中身を代入しています。
前のページで char や short 型のメモリ上のサイズや、変数として持てる数値の幅をお話しましたが、short 型は -32768 ~ 32767、char 型は -128 ~ 127 を持つことができます。
7行目では short 型変数の s にはいっている 100 を、より小さいサイズの char 型に代入しています。
このように、大きい数値をもつことのできる型の数値を、小さい型に代入するときにランク)の「降格」が起こります。

short から char に降格するとき、char 型の範囲内に収まっていれば、そのまま代入ができます。今回のソースコードでも代入できていますね。

もし数値が大きすぎて char の幅に入りきらないときはどうなるでしょうか。
short が 2バイトの環境であれば、ビットでは 2 × 8 = 16 ビットとなります。
char は 1バイトですので、ビットでは 1 × 8 = 8 ビットとなります。
short のほうが 1バイト(8ビット)ぶん大きいので、この分はカットされていまいます。
例えばプログラムを変えて「short s = 200;」 とし、200 を char 型に入れようとすると、「-56」という結果になります。これは char型のもつことのできる範囲である -128~127 にデータが収まらなかったため、収まらなかった分んのビット数の情報が失われてしまってこのようなことになっています。

逆に、char 型で定義した変数の数値(例えば 10 とか)を、short や int 型に代入するときは、問題なくそのまま 10 という数値で代入できます。
持てる幅が大きくなるので、そのままデータをもってこれるということです。
このように、char型で定義した数値を short や int 型などの、より大きいサイズの型に変換するとき型の格(ランク)が「昇格」した、と表現します。

いろいろとお話しましたが、実際にプログラムを書くときに、int 型などを char 型などの小さなサイズの型に代入しようとすると、注意しないとバグの原因になるということです。
特によっぽどの理由がない限りは、このシリーズの今後、数値を取り扱うときは int 型を利用していきます。

演算したときの結果の型

10行目から、12行目では、 char 型、short 型、 int 型が使うバイト数を調べています。
sizeof 演算子については前回お話しているので、よろしければ確認してみてください。

 printf("char 型のサイズは %d バイト\n", sizeof(c));
 printf("short 型のサイズは %d バイト\n", sizeof(s));
 printf("int 型のサイズは %d バイト\n", sizeof(i));

ここで、書いている人のPCでの結果はこのようになっています。
環境によって short や int の結果は変わる可能性があります。

sizeof 演算子の char, short, int 型の結果
型名 サイズ(バイト)
char 1
short 2
int 4

続いて、ソースコードの14~16行目で掛け算や足し算などの演算を行った結果のサイズを見てみましょう。

 // いろいろな型と型の計算結果は int 型になる。
 printf("char + char  の結果は %d バイト\n", sizeof(c + c));
 printf("char * short の結果は %d バイト\n", sizeof(c * s));
 printf("short + int  の結果は %d バイト\n", sizeof(s + i));

すべて 4 バイト(int型と同じサイズ)で表示されたかと思います。

  • char 型と char 型を足した結果は int 型になります。
  • char 型と short 型を足した結果も int 型になります。
  • short 型と int 型を足した結果も int 型になります。

このことからもわかるように、int 型より小さい(ランクが低い)サイズをもつ char や short などを組み合わせ計算しても、内部的には一度 int 型に昇格して計算しているようです。

昇格したり降格したりするのも、CPUの計算が必要ですので、速度面を期待して、charやshort を使うのは意味がないかもしれません。

今回はここまで。お疲れさまでした。

備考:型の格(ランク)の比較参考ルール:

C11 – N1570 を見てみると、変数の型のランクの高低で以下のようなルールが記載されれているようです。備忘も含めて書いておきます。

  • 同じ型だと同じランク
  • 持てる桁数とか精度が高い ≧ 持てる桁数とか精度が低い
  • long long int ≧ long int ≧ int ≧ short int ≧ signed char
  • unsinged int = signed integer type
  • 標準int ≧ 拡張intタイプの同じbit幅
  • char = signed char = unsigned char
  • _Bool ≦ そのほかの標準的なint型
  • Enumerated type = 互換性のある int 型で同じ精度で実装がされているもの

あとがき

今回はここまで。お疲れさまでした。

イチからゲーム作りで覚えるC言語
連載ページ一覧へ
2章18 明示的な型変換(型キャスト)を知る
NEXT : 2章18 明示的な型変換(型キャスト)を知る
2章16 型の長さ、情報量とビットを知る : PREV

非常に参考になったサイトさまや、参考文献など

ページの更新履歴

更新日 更新内容
2018/7/16 ページ初版公開
2018/9/8 アイキャッチ画像、トップ画像を追加