Tosainu Lab

C/C++のプリプロセッサと#include

お久しぶりです.

まず, 7/30〜8/9の間, いろいろあって家族でアメリカに行ってきました.
旅行中の写真はflickrにあげているのでよかったらみてくださひ. 2014_America

さて, C/C++では必要なライブラリ等を読み込むときに#includeというワードを使いますね.
僕もつい最近までは何も気にせずそう書いていたのですが, 今年何度か学校の図書館から借りて読んでいたこの本
c++
この “10章 C++プロプロセッサ” , というかまぁCプリプロセッサの話題を読んでなんてこったいとなったので記事を書くことにしました.

Cプリプロセッサこわい

まず

#include <stdio.h>

int main(void) {
  // なんか処理

  return 0;
}

これをおまじないと教えられている方はこちらの記事などを先に読んでください.
C言語はこうやって教えてくれればいいなって思っただけ

Cプリプロセッサとは

ソースコードのコンパイル前にソースコードに対して行う処理のことをプリプロセスと呼び, その処理を行うプログラムをプリプロセッサと呼ぶらしいです.

Cのプリプロセッサの命令は#で始まるアレ, #defineとか#ifdefとか今回の話題である#includeとかそういうやつです.
例えばこんなC++のコード

#include <iostream>

#define START int main() {
#define END }
#define PRINT(x) std::cout << x << std::endl;

START
PRINT("myon")
END

**は???**ってなるかもしれませんが問題なく動きます.
7〜9行目の部分, これは3〜5行目に定義されたプリプロセッサ命令により, コンパイル前に

int main() {
std::cout << "myon" << std::endl;
}

に展開され, その後コンパイルされます.

このようなコンパイル前に行われる “展開” などの処理がプリプロセッサです.

#include

#includeは “外部のヘッダファイル等を利用するときに使う命令” として普段使われていますが, “指定したファイルの内容をソースコードに挿入する命令” と言ったほうが正しい気がします.

例えばCで#include <stdio.h>しているコードを% gcc -E hoge.cとしてプリプロセッサの展開をすると800行超のコードが生成されますし, C++の#include <iostream>では18,000行近いコードが生成されます. (環境によって行数は異なります)
これは, 標準ライブラリであるstdio.hiostreamのファイルの内容を挿入し, さらにその中のマクロを展開されるためです.

そして, includeするものはヘッダファイルである必要は無いのでこんなこともできてしまいます.

// myon.cc

#include <iostream>

int main() {
  int array[] = {
    #include "arrayfile"
  };

  for (auto&& i: array) {
    std::cout << i << std::endl;
  }
}
// arrayfile

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

実行するとこんな感じ

% g++ -std=c++11 pp001.cc
% ./a.out
1
2
3
4
5
6
7
8
9
10

まとめ

CプリプロセッサはソースコードをC/C++の文法に関係なく強引にソースコードを置換等行うのであんなことやこんなことができてしまうが, 度を超えたマクロは危険であるうえにデバッグやコードの理解を困難にするので良くない.

C++のモジュール

#includeは先ほど示したようにアレだし, その他多くの問題があるので, C++ではモジュールと呼ばれる機能の提案がされているらしい.
これに関しては詳しい方の記事を参考にしてください.

N4047: A Module System for C++
本の虫: 2014-05-pre-Rapperswil-mailingのレビュー: N4040-N4051

良さそうなので実用化に期待したい.

どうでもいいけど

よくC++ソースの拡張子は.cppとされているようですね.
そして, CプリプロセッサはCPPと略されますね.

あれ・・・???

僕はC++ソースの拡張子は.ccを推します.