C/C++で配列の初期化に#includeを使う
データファイルを取り扱う時、そのデータを読んで配列に格納していくのは面倒ですよね。実は、配列の初期化には#includeプリプロセッサが使えます。今回は#includeを使って配列を初期化した時の挙動について書きます。
なお今回のテスト環境は、
- OS : Windows8.1
- IDE: Visual Studio 2013 Express for Windows Deskto
で、includeするファイルはソリューションファイルと同じディレクトリに存在するものとします。
使用コード・ファイル
今回の実験には、#includeで初期化した配列をprintfで各要素を表示するソースコードと、4つの数字","で区切られたデータファイルを使いました。それぞれの内容は下記の通りです。
ソースコード
#include "stdio.h" int sample[] = { #include "sample.txt" }; int main(void) { unsigned int i; unsigned int buf_size; buf_size = sizeof(sample) / sizeof(int); printf("Size of buffer(sample) is %d\n", buf_size); for (i = 0; i < buf_size; i++) { printf("element%2d: %d\n", i, sample[i]); } return 0; }
sample.txtの中身
1,2,3,4
実験1(上記ソースコードをただ実行する)
上記のソースコードを実行すると、#includeプリプロセッサがsample.txtの中身を読んで、配列を初期化してくれることが期待されます。実行してみた結果、実際にそうなりました。この時のコマンドプロンプトの表示を、Fig.1に示します。ファイルポインタを使わなくてよいことから、ファイルポインタ操作(fcloseとか)が不要になるのが便利ですね。
Fig.1 サンプルコード実行時のコマンドプロンプト表示結果
実験2(配列のサイズをsample.txtの要素より少なくしてみる)
#includeがsample.txtの中身を読んでいることから、例えばsample[3]とすると、コンパイルエラーが発生することが予想されます。実際に試してみた結果、Fig.2のようになりました。ファイルの中身を読んでいることがここから分かります。
Fig.2 サンプルコード中の配列サイズをsample.txtの中身より小さくした時のコンパイル結果
まとめ
C/C++では、配列の初期化に#includeプリプロセッサを使い、初期化時にファイルの中身を直接配列に保存することができます。これにより、ファイルポインタの解放忘れがなくなり、メモリ関係のトラブル要因を1つ消すことができます。また、実行環境でファイルを読まなくてよいので、秘密なデータを配列に保存したい時、セキュリティの面から有用だと思います。
また、配列サイズを指定する・しないをうまく使い分けることで、様々なメリットがあると考えます。自分の考えとしては、
-サイズを指定する →読み込むファイルの中身のサイズが固定
→読み込むファイルが想定したファイルか、フォーマットになっているかが確認できる
-サイズを指定しない→読み込むファイルのフォーマットが変わっても、柔軟に対応することができる
というメリットがあると思います。
ただし、#includeを使って配列を初期化すると、コンパイル時に配列サイズが決まってしまいます。つまり、ファイルの中身を変更しそれを配列に反映したい時、再コンパイルが必要になります。この点には注意が必要になります。