相互インクルード?循環インクルード?
「よくやってしまう」ほどではないけど、昨日の分も含めて過去に
2回ほどやってしまった事がある気がする。
ちょっとしたうっかりミスと、インクルードする順番が違う時に限って起こる。
症状
自分で定義した型のデータを作れない。コンパイラエラーがでる。
エラーメッセージによると多分、コンパイラが自分で定義した型名を、型名だと思ってない。
BCC5.5だと
>エラー E2139 header2.h 8: 宣言に ; がない
とか、
>エラー E2141 header2.h 12: 宣言の構文エラー
などと表示されると思う。
例
/* header1.h */ #ifndef __header1_h__ #define __header1_h__ /* ぼーっとしていて、意味も無くincludeしちゃった */ #include "header2.h" typedef int h1_type; #endif /* __header1_h__ */
/* header2.h */ #ifndef __header2_h__ #define __header2_h__ #include "header1.h" struct st_aiueo{ /* header1.hにあるデータ型 */ h1_type data; }; #endif /* __header2_h__ */
/* include_each_other.h */ #if 0 /* うまくいくパターン */ # include "header2.h" # include "header1.h" #else /* いかないパターン */ # include "header1.h" # include "header2.h" #endif int main(void) { /* Do nothing. */ return 0; }
何が悪いか
BCC5.5がある人は、cpp32 <ソースファイル名> としてみると、
ヘッダファイルが結合された形で出力されます。
が、やってみたら、行頭に/* 元々のファイル名 */
がついて見づらかったので手動でまとめてみました。
/* #includeを使わずに、全部まとめてみた */ /* header2.h にあった内容 */ struct st_aiueo{ /* header1.hにあるデータ型 */ h1_type data; }; /* header1.h にあった内容 */ typedef int h1_type; int main(void) { /* Do nothing. */ return 0; }
もし二重(多重)インクルード防止コードが無かったら
無限に互いをインクルードするのかもしれませんが、その点は大丈夫です。
上でまとめて書いたコードのように、まず最初にheader2.hの内容がくるので、
header1.hで定義されているh1_typeというデータ型はまだ定義されていないという事になります。
これはheader1.hが、まずheader2.hをインクルードしてるからです。
(そしてheader2.hは多重インクルード防止コードにより、事実上header1.hをインクルードできない。)
まとめ
例のやつで、もしinclude_each_other.cが2つのヘッダファイルをインクルードする順番が違えば、
この問題は起こりません。それが厄介なところです。
これはうっかりミスですが、設計上そうしなくちゃいけない事なんてあるんだろうか…。
(お互いがお互いを必要とするような場合とか?)まあ難しい話はわかりませんけどね。