プリコンパイルヘッダの話

[戻る]
bun 2007/12/19(水) 14:11:12
プリコンパイルヘッダの話は非常に興味深いので、別スレッドをおこすことにし
ました。この機会に、私にとっての10年来の謎を解き明かしたいと思ったから
です。

プリコンパイルヘッダの話をヘッダファイルに限定(ヘッダファイル以外も可能
らしい)すると、ヘッダファイルというのは、一般的な使い方では、以下のよう
なものが含まれます。
  ・各種定数(#deineで定義されるもの)
  ・グローバル関数のプロトタイプ宣言
  ・クラス定義
  ・インライン関数

私の認識では、コンパイルという作業は、関数群(グローバル関数, メンバ関数)
をobjファイルに変換すること、および関数内で使用されている、関数外の変数
や関数が、ヘッダファイルに実際に定義されているかを調査していると思ってい
ます。
(細かくは#defineマクロ展開なども含むでしょうが、長くなるので省きます)

そして、リンクでは、関数内で使用されている関数外の変数や関数が実際にobj
ファイルやlibファイルに存在しているかを確認し、全ての存在が確認できたら
実行ファイル(exe, dll)形式に変換出力しているものと思っています。

以上の認識に従うと、私の中ではヘッダファイルをコンパイルした結果、形とし
て残るものはobjファイルだけ(libファイルはリンク後にできるよね?)という結
論に達します。
つまり、プリコンパイルヘッダというのが何者であろうと、そこにはobjファイル
に含まれるであろうものしか含まれないのでは?ということです。

では、objファイルに含まれるものとは、具体的には何?
クラス定義やプロトタイプ宣言などはあくまで定義にすぎず、実体を持ちません。
そうなると、含まれるものは、関数の実装やら変数の実体などだけかな?

以上の考察からして、一般的な作りのMFCプログラミングでは、ヘッダファイルに
グローバル変数や、グローバル関数を置きませんから、残るのはインライン関数
だけかなと思った次第です。
これが、この前の発言に至った経緯です。

でも、よく考えると、これはMFCを使う側の理論で、MFC自体にはグローバル変数
や、グローバル関数も含まれているでしょうから、それらもstdafx.hのプリコン
パイルヘッダには含まれるのかな?と思ったりしています。

一度、自分でプリコンパイルヘッダを作ってみれば、分かることかもしれません
が、その気力はないのに、結果だけ気になる不精者ですので、お話におつきあい
願えたらうれしく思います(^-^)

Kerry 2007/12/19(水) 14:40:35
「プリコンパイル」処理が通常のコンパイルと同じ処理とは限らない
でしょうし、プリコンパイルの結果出力されるPCHファイルがOBJ
ファイルと同じ形式であるとも限らないのではないでしょうかね。

あくまで私の想像ですが、プリコンパイル処理はインライン関数の
コンパイル以外にも、ネストしたインクルードの展開とか、クラスや
関数定義の構文解析、マクロシンボルのテーブル作成なども行っている
のではないかと思われます。

tetrapod 2007/12/19(水) 14:54:16
難しく考えすぎだと思う

#include <hoge.h> したら、その中にあるものを使うことができるようになる。
使えるかどうかと、実際に使うかどうかは関係ない。
実際に使った結果のみが .obj ファイルに書き出されるのに対して
コンパイルの最中には使う可能性があるものすべてを保持してなきゃならない。

#include <window.h> で10000行近いソースコードが処理される。
複数のファイルのコンパイルの際に毎回10000行もの
「変更されないソースコード」 (= windows.h や MFC など) を処理するのは
単なる時間の無駄なので考えられたのがプリコンパイルヘッダ。
プリコンパイルヘッダ中には「ヘッダファイルを処理した中間結果すべて」
すなわち、使われる可能性があるものすべてが入っている。
そのうちの実際に使ったものだけが .obj に入っている。

だから .obj は小さいのに対して .pch はあんなに巨大。

maru 2007/12/19(水) 16:21:49
> 以上の考察からして、一般的な作りのMFCプログラミングでは、ヘッダファイルに
> グローバル変数や、グローバル関数を置きませんから、残るのはインライン関数
> だけかなと思った次第です。
前回の「インライン関数」云々の話がこのような考えから出てきたことは理解
いたしました。

プリコンパイルドヘッダファイルに付いては tetrapod さんが書いている通り
そんなに難しく考える必要はないと考えます。私の考えも tetrapod さんと一
緒で、「ヘッダファイルを処理した中間結果すべて」が入っていると思います。
それで、前回の bun さんの書き込みがインライン関数だけをとりあげたのが不
思議に感じられましたわけです。

前回、
>「まるで」自信の無いことを掲示板に書くのは如何かと。
と書きましたが、これはチョット言いすぎたかなと反省しています。
気分を害されたのならば、この場を借りて謝罪させていただきます。
申し訳ありませんでした。

bun 2007/12/19(水) 22:51:15
Kerry様、tetrapod、maru様

どうやら私の頭が固かったようです。
お2人の話で見えてきた気がします。要するに、普通のコンパイルとは全く違ったもの
だということですね。
確かに、通常のコンパイルでは全てのヘッダファイルの依存関係を調査し、展開せねば
なりません。その作業だけでも結構な時間がかかりそうですし、それを中間形式(objフ
ァイルとは違う形式かつ再コンパイル時に再利用性の高い形式)で保存できれば、有効性
は高そうです。
それが、maru様のおっしゃっている、「ヘッダファイルを処理した中間結果すべて」と
いう言葉の意味ですね。

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

bun 2007/12/19(水) 23:20:30
maru様

ちょっとした行き違いがありましたが、本当に問題なのは、私でもmaru様でもないと思
っています。一部のマナーのない利用者だと思っています。

マナーの悪い人が、自信のないことをさも、事実であるかのように書き、他の人を惑わ
せることがあるのは事実ですし、私の発言がそのようにとられても仕方ないのかもしれ
ません。
しかし、今回の場合、私の考えとして述べていることは話に含めていますし、それでみ
なさんの意見を聞いてみたかっただけのことです。それが否定されてしまうと、私と同
じように発言したい人が発言できなくなってしまいます。一番、気がかりだったのはそ
この部分です。

ただ、今回の件は、私もちょっと行き過ぎだった気がします。
申し訳ありませんでした。

maru 2007/12/19(水) 23:52:40
「ヘッダファイルを処理した中間結果すべて」と書いたのは tetrapod さんなん
ですけどね。

> 要するに、普通のコンパイルとは全く違ったものだということですね。
私は逆にプリコンパイルは普通のコンパイルと余り変わらないのではないか
と思っています。つまり以下のような考え。
プリコンパイル済みヘッダの作成では、通常のコンパイルを途中まで実行し、
コード生成のために作成したシンボルテーブル等をバイナリで保存しておく。
プリコンパイル済みヘッダを使ったときはそのバイナリをロードすることに
よってコンパイル時間を短縮する。
こんな風に考えるのが普通ではないですかね。

wood 2007/12/20(木) 06:53:30
話の論点はそれてしまうのかも知れませんが
PCHはMSにしか無いものと思ってますが、ほかのコンパイラにも機能
あるんですかね

LINUX等で使用するGCC などは、どうなんでしょうか?

MS−C Ver3 位のときは、なかったよね こんな機能

tetrapod 2007/12/20(木) 08:44:36
PCH というもの自体は他のコンパイラにも存在する
むしろ VC++ の .pch ファイルが独特で使いづらいのかもしれない
http://sgry.jp/pgarticles/precompiled_header.html

bun 2007/12/21(金) 08:51:09
[[解決]]
皆様、貴重な意見をありがとうございました。

「プリコンパイルヘッダ」っていったい何なのだろう?
漠然とですが、ず〜っと思っていた謎の核心にかなり迫れた気がします。

細かいことを言うとずっと奥が深いのでしょうが、憶測だけで細かい話をしても意味は
ありませんので、このくらいの話で十分かと思います。

皆様の意見を聞いて、私なりに考察した結果、コンパイル作業を可能な限り、先まで進
めて、その結果をバイナリ形式で保存しておくというのが一番的を得ているような気が
します。
次回のコンパイル時は、バイナリ形式のファイルを読み込むだけで、コンパイルが途中
まで進んでいるのだから、確かに非常な高速化になりそうです。

それでは、失礼いたします。

古いスレッドには追加発言できません。