C言語やC++で使われている二値型であるbool変数。trueとfalseという二値が収納できるのは分かりますが、メモリーの中でどのように保管されているのかは知っていますか? 環境によって違うと思いますがWindowsでは1バイトだったりします。
Bool型のメモリー確認
C言語は低レベルな言語なので、メモリー関連の操作が分かりやすいです。正確にはブラックボックス化されていないので調べようと思ったら力づくで調べることも出来てしまいます。
今回はC++から実装されたbool型がどのようにメモリーに展開されているかを実験していきます。
今回は嬉しいUnion
C言語には構造体という変数をグループ化する方法論があります。こちらは比較的分かりやすいですが、そのときに「共用体」というものを習わなかったでしょうか?
構造体はstructですが、共用体はunionです。ユニオンって言葉も組合って意味があるので、グループ化の一種に思えますが正直全然違います。そして、普通のプログラマにとっては使い所が分からない仕組みでもあります。
共用体とは、同じメモリーを複数の変数で使う宣言のことです。
仮にこんなコードを実行すると、小文字のaからoまでを出力します。
- #include<stdio.h>
- union test {
- char str[20];
- unsigned int num[5];
- };
- //bool型がどのようにメモリーに配置されているか確認。
- main(){
- union test s;
-
- s.num[0]= 0x64636261;
- s.num[1]= 0x68676665;
- s.num[2]= 0x6C6B6A69;
- s.num[3]= 0x006F6E6D;
-
- printf("%s\n",s.str);
- }
ここでキーになるのは 共用体testは str文字列と符号なし整数の numを同じメモリーで共用しています。つまり、str文字列に書き込みをすればnum型も変更されるしその逆もあります。
今回はnum型に16進数で数字を書いています。64636261と16進数で書いています。これはアスキーコードで61は小文字のa、64は小文字のdに相当します。
Windowsはリトリエンディアンなので、数字で言う低い桁がバイト単位で逆転します。このため、64636261と整数型に入力した場合、それを文字列として解釈すればabcdとなります。そして
s.num[3] = 0x006F6E6D を代入しています。これはnmoを意味します。最後のゼロは文字列の約束事で、文字列の終わりは必ずゼロにする約束です。これを守ることを前提に関数などが実装されています。プログラミングは性善説です。
本題のbool型のメモリー
以下が実験コードです
- #include<stdio.h>
- union test {
- unsigned int bits;
- bool bit[4];
- };
- //bool型がどのようにメモリーに配置されているか確認。
- main(){
- union test b;
-
- b.bits = 0;
- b.bit[0] = true;
- b.bit[1] = false;
- b.bit[2] = true;
- b.bit[3] = true;
-
- printf("%x\n",b.bits);
- }
このコードは、共用体で符号なし整数とbool型の配列を共用しています。これを実行すると
1010001
と出力されます。ということはBool型はビット単位でのデータ保存ではなく、バイト単位であることが分かります。なのでメモリー節約が目的ではないということが分かります。
考察
実はビット単位でデータを保存すると読み書きが遅くなります。コンピュータってバイト単位で読み書きするのが効率が良いです。そのため、bool型のような1ビットの値でも1バイトを使って収納するほうが効率が良いです。