【ゲーム開発のためのC#入門講座・基礎強化編】値型を理解してメモリに優しくなろう【#2】

2022-01-093.0_C#基礎強化編

おさらい

変数の型とはどういうものか、皆さん覚えてますか?

せっかくなので、基礎学習編で学んだことをおさらいしてみましょう。

変数の型というのは、変数という記憶装置の種類のことです。
(中略)
そのデータがどんな特徴や性質をもっているのか教えてあげないと、コンピュータはそれをきちんと処理することができないんですね。
だから読み書きするデータの種類がわかるように、これはこういうデータなんですよーっていうのをコンピュータに教えてあげる必要があります。
それが型と呼ばれるものです。

いわば、コンピュータがデータを取り扱うための説明書のようなものでしたね。

例えばint型は整数を扱える型です。小数点以下は扱えません。

一方で、float型は小数点以下の数値も扱える型です。

え、だったらint型いらんくない? という疑問については、有効桁数が違うからfloat型一択という訳でもないんですよーという話をしましたね。

有効桁数
int-2,147,483,648 ~ 2,147,483,647(圧倒的桁数ですね)
float全体で7桁まで(整数が3桁なら、小数点以下は4桁まで)

ここら辺の使い分けは慣れないとわりと面倒です。どうせなら整数も小数点以下の数値も扱えて桁数も無限に設定できる型がひとつだけあればいいのに、と思われるかもしれません。
この理由はC#が静的型付け言語である理由に繋がってくるので、いずれ解説しますね。

今回がその解説回となります。

実はもっとたくさんある整数型

整数を扱える型を整数型と言ったりもするのですが、実はC#にはint以外にもたくさんの整数型があります。

値の範囲
byte0 ~ 255
short-32,768 ~ 32,767
int-2,147,483,648 ~ 2,147,483,647
long-9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807

上記以外にもさらに6個程あるんですが、あまり使う機会がないので、代表的な整数型を挙げさせてもらいました。

違いを確認してみると、どうも扱える値の範囲が異なるようですね。

でも考えてみると、一番値の範囲が広い「long」であれば、それ以外の型の値はすべて扱うことができるんですよね。だったらそれこそlong一択でよくない? と思えてしまいます。

どうして同じ整数を扱うのに、こんなにいくつも型が用意されているのでしょう?

それは、型という情報の中にメモリの必要サイズも含まれているからなんです。

メモリの観点で型の価値を考えてみよう

前回の記事で説明のあった通り、コンピュータはメモリと呼ばれる領域でプログラムの一時的なデータ管理を行っています。変数に格納したデータも、コンピュータの内部的にはメモリに保存されているんですね。

今後、メモリの話をする際はこんな感じのイラストで進めていきます。プログラミングでは1byte(=8bit)が最小単位になるので、箱ひとつで1byte(バイト)です。

それでは話を戻して、例えば「整数も小数点以下の数値も扱えて桁数も無限の数値」のように、格納するデータの最大サイズがわからない変数をメモリに保存しようとするとどうなるでしょう?

変数Aをメモリに保存
変数Bをメモリに保存
途中で最大サイズが変わると困ってしまう!

こんな風に、割り当てられたメモリサイズが足りなくなってしまうかもしれません。そのせいで別の変数のデータを上書きしてしまうなんてあってはならないことですよね。

かといって、そういうことが起きないよう、とにかく余裕をもってメモリを確保しようとすると、今度は無駄に保存領域を消費してしまう可能性があります。

余分に箱を用意すると……
無駄に保存領域を消費してしまうリスクがある

すごく非効率的ですよね。

時代の進歩によって現代のメモリサイズはかなり巨大化していますが、昔は本当に小さな容量でした。こんなことを繰り返していたらすぐにメモリがパンクしてしまいます。

バージョン最低要求メモリサイズ
Windows958MB
Windows9816MB
WindowsME32MB
WindowsXP128MB
WindowsVista512MB
Windows71GB(1,024MB)
Windows82GB(2,048MB)
Windows102GB(2,048MB)
Windowsの最低要求メモリサイズ一覧

Windows95の最低要求メモリサイズ8MB……今思うとよく動いてたなって感じですね。

それではもし、格納するデータの最大サイズが明確にわかっていたらどうでしょう? 例えばlong型は最大で8個、int型は最大で4個と決まっていたとしたら?

long型は最大で8byte
int型は最大で4byte
必ず確保したメモリ領域に収まるから困らない!

事前に最大サイズがわかっていれば、その数だけメモリを確保しておくことで、効率よくメモリを使うことができますね!

このように、必要なメモリサイズが明確な型のことを値型といいます。

色んな値型を見てみよう

下記はC#で扱える代表的な値型の一覧です。

メモリサイズ(byte)値の範囲
byte10 ~ 255
short2-32,768 ~ 32,767
int4-2,147,483,648 ~ 2,147,483,647
long8-9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807
float4正負および桁数により変動
double8正負および桁数により変動(floatより桁数が多い)
decimal16正負および桁数により変動(10進型)
char21文字(表示内容は文字コードによって変化)
bool1true / false

扱える値の範囲(桁数)が狭いほど必要なメモリサイズが小さく、広いほどメモリサイズが増えているのがわかりますね。

ちなみにbyteが0~255なのは、1byte=8bitの二進数で表せる値がちょうど0~255だからです。

他の型の有効範囲もすべて同じ理由で、二進数的にはキリがいいけど十進数的には中途半端な数字になっています。

メモリに優しい型選択を考えてみよう

もし皆さんがプログラムを組む時、このデータは最大でも255(1箱分)を超えることはないな、とあらかじめわかっているとしたら、どの型を使いますか?

そのデータを「long(最大8個)」や「int(最大4個)」で扱うこともできますが、絶対に255 (1箱分) を超えることがないのなら、余分なメモリ領域を確保していることになりますよね。

long型だと8個確保することになるが……
もし1個で十分なら、7個分が無駄になってしまう

ですが、ここでbyte型を選択すれば、必要最小限のメモリ消費で済ませることができます。

long型ではなくbyte型にしてあげると……
不必要なメモリ消費がなくなり、空きを多く残せるようになる!

つまり値型に色んな有効範囲の型が用意されているのは、扱いたい値の範囲に応じて効率よくメモリを活用するためだったんですね。

そしてこれが、型を明示するという静的型付け言語のメリットのひとつでもある訳です。

Unityでの活躍ポイント

先程お伝えした通り、時代の進歩によってメモリサイズはかなり巨大化しています。そのため、「byte(1byte)」と「long(8byte)」を使い分けるなんて細かいこと、現代においてはやる必要ないという意見もあります。

それはそれでひとつの事実です。

なので、すべての処理で無理してまで使い分ける必要はないです。

ただ、例えば100万件を超える大量データを処理しなければいけない時や、アクションゲームのように1f(60fpsなら1/60秒)で素早く大量の処理を終えなければいけない時に、知識と選択肢があることは武器になります。

せっかく作るゲームですから、いざって時にはやれるだけのことを全部やれるようにしておけるといいですよね。

実践演習

それでは試しに、最適と思える型を選択してみましょう。

演習①

仕様

0~400までの数値を扱う予定の変数「result」があります。
適切な型を設定してあげてください。

テンプレート
public class Hello{
    public static void Main(){
        // ↓適切な型を設定してみよう!
        型 result = 0;
        result += 357;
        System.Console.WriteLine(result);
    }
}

演習②

有効範囲を超えた値を設定するとどうなるのか、確認してみましょう。

下記の実行結果がどうなるのか、確認してみてください。

public class Hello{
    public static void Main(){
        byte result = 255;
        result += 1;
        System.Console.WriteLine(result);
    }
}

答え合わせ

演習①の答え

public class Hello{
    public static void Main(){
        // ↓適切な型を設定してみよう!
        short result = 0;
        result += 357;
        System.Console.WriteLine(result);
    }
}

演習②の答え

出力エリア

0

一周回って0になってしまいました!

メモリサイズだけでなく、有効範囲を超えないようにするのも型選択の大事なポイントですね。

まとめ

  • 型という情報の中にメモリの必要サイズも含まれている
  • 事前に最大サイズがわかっていればメモリを効率よく扱うことができる
  • 必要なメモリサイズが明確な型のことを値型という
  • 値型に色んな有効範囲の型が用意されているのは、扱いたい値の範囲に応じて効率よくメモリを活用するため
  • 現代においては、すべての処理で無理してまで細かく型を使い分ける必要はない。が、理解しておくといざって時に武器になる

それでは、今回もお疲れ様でした!

また次の記事でお会いしましょう!

お借りした素材一覧

この記事では下記サイト様の素材をお借りしています。

ありがとうございました!

かわいいフリー素材集 いらすとや (irasutoya.com)

Posted by 夕目紅