前書き
次のことが起こった。
- windows用アプリケーションフレームワークのMFCを使い、ヘッダファイル(
.h
)にクラスの定義を書き、コンストラクタを別ファイル(.cpp
)に分割しようとしていた。 - しかし、ヘッダファイル中にあったときは動作していたプログラムが、分割したところコンパイルが通らなくなった。
- 原因は分割した
.cpp
の中で、stdafx.h
の上の行でクラス定義のヘッダファイルをインクルードしていたこと
そこでstdafx.h
について調べたことをメモする。
結論は、stdafx.h
のインクルードはファイルの先頭でなければならない。
上記の問題はC++(MFC)で自作クラスをクラス定義(.h)と関数実装(.cpp)に分割したいで質問し、回答をいただいて解決した。
プリコンパイル済みヘッダについて教えてくださったChironian様、ご回答頂いた皆様、改めましてありがとうございました。
プリコンパイル済みヘッダファイル
stdafx.h
およびstdafx.cpp
は、プロジェクト名.pch
で生成されるプリコンパイル済みヘッダファイルとstdafx.obj
で生成されるプリコンパイル済みタイプファイルをビルドするためのファイル。
プロジェクト名.pch
たちはDebug
フォルダ内等に生成される。
stdafx.h
頻繁に使われるが、変更は頻繁でないインクルードファイルのためのインクルードファイル。
このファイルの中で_AFX_NO_XXX
というマクロを定義してはいけない。(ファイルを覗くと最初からそんな定義がいくつか見える。)
stdafx.cpp
#include "stdafx.h"
が書いてある。
プリコンパイル済みタイプのインクルードファイルを追加する。(このファイルに必要なヘッダを追加するように読めるが、他のソースではstdafx.hに追加すると読める文も出てくる。どっち?)
プリコンパイル済みファイルというのは、プリコンパイル済みファイルを必要とするファイルのコンパイル速度を速めるためにある。最初にプロジェクトをビルドしたら、(プリコンパイル済みファイルが生成され、)その後は最初よりもっと高速にビルドできる。
手動設定と注意
stdafx.h
は、すべての .c と .cpp ファイルでインクルードされるべき-
Visual Studio
で新規プロジェクトを作成する場合stdafx.h
とstdafx.cpp
が自動で作成され、コンパイルに必要なすべてのオプションは定義されている。 - 手動設定は、プロジェクトのプロパティから次の画像のように設定し、下記1~3を実行して有効にできる

- stdafx.h ファイルを作成し、プロジェクトに追加します。事前に前処理したいヘッダーをこのファイルにインクルードします。
- stdafx.cpp ファイルを作成し、プロジェクトに追加します。このファイルは次の 1 行のみを含みます: #include “stdafx.h”。
- [すべてのオプション] で stdafx.h 向けに設定を変更: [プリコンパイル済みヘッダー] オプションに “作成 (/Yc)” を設定します。
各ファイルに #include “stdafx.h” を追加する必要があります
そして、
**“stdafx.h” ヘッダーは、各 .c や .cpp ファイルにインクルードする最初のファイルでなければいけません。
なぜ最初にインクルードするのか
例1
例として次のように解説されていた。
-
"stdafx.h"
より前のにインクルードされたファイルに#define bool char
があるとする。 - 全ての
bool
がchar
に置き換えられる - プリコンパイル済みヘッダが想定して準備していた「めったに変更されないが頻繁に使用される処理」も
bool
-->char
の変更を受ける - プリコンパイル済みヘッダー全体の構成が壊れる
このようなことを防ぐ理由がある。他にも理由があるらしい。
例2
次のようなコードがあるとする
(#include "stdafx.h"
が先頭ではない!)
int A = 10;
# include "stdafx.h"
int _tmain(int argc, _TCHAR* argv[]) {
return A;
}
これはエラーになる
error C2065: 'A' : 宣言されていない識別子
なぜなら、
これは、#include “stdafx.h” (この行を含む) 以前のすべてのテキストが、プリコンパイル済みヘッダーであると考えられます。このファイルをコンパイルすると、コンパイラーは #include “stdafx.h” 以前のテキストを .pch ファイルで置き換えようとします。その結果、”int A = 10;” の行は失われます。
正しくは
# include "stdafx.h"
int A = 10;
int _tmain(int argc, _TCHAR* argv[]) {
return A;
}
ソース:
StdAfx.h に関する考察
なおプリコンパイル済みヘッダに関する問題には、プロジェクト全体を再コンパイル(リビルド)すると解決するものもあるらしい。