#include の魔力

何気なく呟いた言葉が確変状態になっていました。

それで、反応を眺めていると「何をやってるか分からない」と言うものがいくつかあったので、一応簡単な補足説明を載せておきます。

#include は指定したファイルの内容をその位置に追加します。

1, 2, 3,
4, 5, 6,
7, 8, 9,

例えば、上記の内容を hoge.csv と言う名前で保存して、

int hoge[] = {
#include "hoge.csv"
};

と記述すると、(プリプロセスが終了すると)以下のように記述した事と同じになります*1

int hoge[] = {
1, 2, 3,
4, 5, 6,
7, 8, 9,
};

このように、#include を利用することによって、内容が変化しない*2データ配列などの定義を自力で打ち込んだりコピペしたりせずに済むようになります(なることがあります)。s/int/const char*/ と言う反応がありましたが、プリプロセッサは文字列を置換しているだけなので、コンパイル時には上記のデータの各要素は「文字列」ではなく「整数」として認識されます。

ちなみに、結構多くの反応があった通り、hoge.csv と言っても「csv っぽいファイル」なだけで *.csv だったら何でも OK と言う訳ではありません。最大の問題点は各行の最後の要素の後にもカンマが必要なことで、多くの *.csv ファイルで上記のような使い方をするためには、あらかじめ何らかの修正を加えておく必要があります。

使用用途については・・・私自身もこう言う書き方をした事がないのであまり具体的には言えないのですが、何らかのマッピングファイルのようなものが既に公開されていて、そのデータを常にロードして使用しなければならないようなプログラムを書く際には、上記のような書き方にしておく方が良いのかなぁと思いました。後は、反応を見ていると、ゲームプログラミングの領域では割と使われている(?使われていた?)技法のようです。

というか、C/C++のマクロって強力過ぎ。

誰かさんの要望でいま Unicode ⇔ ShiftJIS の処理とか書いてるんだけど、そこでも...

http://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP932.TXT

...から拾ってきたテキストファイルを...

open(TXT, "CP932.TXT");
open(CSV, "> cp932.csv");
  while($line = <TXT>) {
    if ($line =~ /^(0x.*)\t(0x.*)\t#(.*)/) {
      print CSV "$1, $2,\t\x2F\x2F\t$3\n";
    }
  }
close(TXT);
close(CSV);

...なんてperlのスクリプトでCSVファイルに変換したものを...

int cp932[] = {
#include "cp932.csv"
};

...なんて形でインクルードできちゃったり。

http://ml.tietew.jp/cppll/cppll/article/5730

実例としては、twitter でも呟きましたが http://tricklib.com/cxx/ex/babel/ などで確認する事ができます(実際に #include されているマッピングファイルは、scoremap.csvcp932.csvutc.csvapple.csvsjis-euc.csveuc-uni.csv)。

*1:twitter の都合上、改行を抜いて呟きましたが、実際は上記のように改行する必要があります。

*2:*.csv ファイルの内容が変化した場合、再コンパイルする必要があります。