No.5ベストアンサー
- 回答日時:
これまでの回答でほぼ出揃っているように思いますが、ある程度の規模のソフトを開発するような場合の定石のようなものを示しておきます。
# ソースファイル数が数百以上になるような規模のプロジェクトでは、
# 普通にやっていることだとは思いますが。。。
機能分割やモジュール分割するときに、内部公開用ヘッダと外部公開用ヘッダを用意する場合があります。
こうすることで、機能部外に必要以上の情報を公開する必要もなくなり、No3 buihyaku さんのおっしゃるようなことを極力避けることができるようになります。
たとえば、こんな感じ。
【HOGE 機能部】
〔HOGE_A モジュール〕
(外部公開用ヘッダ) hoge_a.h
(内部公開用ヘッダ) hoge_a_i.h
〔HOGE_B モジュール〕
(外部公開用ヘッダ) hoge_b.h
(内部公開用ヘッダ) hoge_b_i.h
【PIYO 機能部】
〔PIYO_Z モジュール〕
(外部公開用ヘッダ) piyo_z.h
(内部公開用ヘッダ) piyo_z_i.h
で、こんな感じでヘッダファイルをインクルードさせます。
========================================================
[hoge_a.c]
--------------------------------------------------------
#include "hoge_a_i.h"
#include "hoge_b_i.h"
#include "piyo_z.h"
========================================================
[hoge_b.c]
--------------------------------------------------------
#include "hoge_a_i.h"
#include "hoge_b_i.h"
#include "piyo_z.h"
========================================================
[piyo_z.c]
--------------------------------------------------------
#include "hoge_a.h"
#include "hoge_b.h"
#include "piyo_z_i.h"
========================================================
また、この場合、こんな感じで内部公開ヘッダに外部公開ヘッダをインクルードしておきます。
========================================================
[hoge_a_i.h]
--------------------------------------------------------
#include "hoge_a.h"
========================================================
[hoge_b_i.h]
--------------------------------------------------------
#include "hoge_b.h"
========================================================
[piyo_z_i.h]
--------------------------------------------------------
#include "piyo_z.h"
========================================================
さて、上記のヘッダファイルの構築法ですが、下記のように考えればよいのではないでしょか。
(1) 最初は 1ファイルの小さなソースファイルでプログラムを作成。
この場合、ヘッダファイルを作成する必要はありません。
(2) 機能拡張していくと、1ファイルではメンテナンスしきれないくらいコードが肥大化してくるため、機能ごとに別ファイルにする (機能分割)。
この場合、機能ごとにヘッダファイルが必要になる。
(3) さらに機能部に対して機能拡張していくと、やはりコードの肥大化によりメンテナンスが困難になってくるため、機能部をモジュールごとに別ファイルにする (モジュール分割)。
この場合、必要に応じてモジュールごとのヘッダファイルを用意する。
また、(2) で作成したヘッダファイルのうち、分割したモジュールに関連する部分を「外部公開ヘッダ」、モジュール分割により新たに必要になったヘッダファイルを「内部公開ヘッダ」として作成する。
とりあえず、ご参考まで。
長々と失礼しました。
No.7
- 回答日時:
プロトタイプ宣言の例です。
まず、xxx.cというファイルが一つだけの場合です。xxx.c内の関数fnc1()から同じくxxx.c内のfnc2()を呼び出すとき、fnc2()のほうが後ろに定義されてたら、fnc1()よりも前にfnc2()のプロトタイプ宣言を書きますよね。
次に、yyy.cというファイルがもう一つあって、その中のfnc3()からxxx.cのfnc2()を呼び出すとき、fnc3()の前にfnc2()のプロトタイプ宣言を書けばコンパイルは通りますが、本末転倒です。プロトタイプ宣言はコンパイル時の型チェックのために書くのに、yyy.cで好きなように書くと本来のxxx.cでの定義とずれる可能性があるからです。
そこで、fnc2()のプロトタイプ宣言は定義のあるxxx.cが提供することにして、xxx.hにfnc2()のプロトタイプ宣言を書きます。それを、yyy.cやその他、fnc2()を使いたいファイルがインクルードすれば、コンパイル時に本来の目的のfnc2()の型チェックを行えることになります。
プロトタイプ宣言以外の#defineやstruct定義も同様ではないでしょうか。各ファイル内でそれぞれ同じものを定義してもコンパイルは通りますが、提供元がヘッダとして公開してそれを共有することでファイル間で定義を一意のものとする、という感じではないでしょうか。
逆に言えば、他のファイルに公開したくないstructなどは.cファイルのほうに記述することで、隠蔽できます。
No.6
- 回答日時:
まともな回答は既にされているので、
邪道な解答を書きます。
ヘッダーファイルの話でないので質問の趣旨から外れるかもしれませんが。
状況
10本のプログラムがあり、main関数はほとんど同じ。
それらのmain関数は頻繁に変更され、変更内容は同じ。
このとき、main.cppでそのほとんど同じ内容を書き、各プログラムではそれをincludeするようにした。
異なる部分は#if definedを使って切り分けたが、
その部分もごくわずか。
このようにして、main.pp1本の修正だけで済むようになった。
p.s. 根本的な問題(似たようなプログラムをたくさん作るのがまずい)はおいときます。だって、私が作ったんじゃないですもの。
No.4
- 回答日時:
ヘッダファイルの作り方は人によって方針が異なりますので、回答者間で矛盾した回答が得られる可能性が高いかと思います。
それを踏まえて...まず、C専用か、C++専用か、C/C++両用かによって、若干作り方が異なります。
C専用の場合、ファイル名は~.hにすることが多いかと思います。C++で使うことを想定しなくてもよいので、比較的シンプルな作りになるかと思います。
C++専用の場合、ファイル名は~.hの他、~.hppや~.hhなどが使われます。クラス指定子や、インライン関数定義、(exportがサポートされないので)テンプレート関数定義などがヘッダファイルの中で行われます。
C/C++両用の場合、基本的にはC専用と同じですが、__cplusplusマクロが定義される場合には、外部宣言をextern "C" {~}で囲んだり、マクロの使用を最小限に抑えたりと、C/C++のどちらにも通用する作り方をする必要があります。
どの場合にも共通なのは、多重インクルードを抑止するための仕組みが必要です。
#ifndef XXX
#define XXX
...
#endif
といった書き方ですが、ここで大切なのは、マクロ名XXXは下線(アンダースコア)で始めないことです。下線で始まるファイル有効範囲(C++では大域的前空間有効範囲)の識別子は処理系と標準ライブラリに予約されており、そうした識別子をマクロとして定義した場合の動作は未定義になってしまうからです。
もう一つは、(#endifの後など)ファイルの終端は必ず改行で終わることです。これも、空でないソースファイルが改行文字で終わらない場合の動作は未定義になるからです。
ヘッダファイルからヘッダファイルのインクルードについては意見が分かれるところですが、私の場合は積極的に行っています。共通する内容を複数のヘッダファイルに分散して記述すると保守性が下がることが理由です。
現在のコンパイラやPCの性能からすれば、プリプロセスに要する時間が問題になることはほとんどありませんが、どうしても気になる場合は、インクルードの際に、
#ifndef XXX
#include "xxx"
#endif XXX
とすれば、無駄な処理を最小限に抑えることができます。
No.3
- 回答日時:
あるソースファイルで定義された関数を他のソースファイルでも使いたい場合に、その宣言をヘッダファイルに記述し、それを使用したいソースファイルでインクルード(取り込み)します。
また、複数のソースファイルで共通に使用される定義は複数のソースにそれぞれ同じ定義を記述するのではなく、ひとつのヘッダに記述してそれぞれのソースファイルの先頭でインクルードします。こうすることで、定義の内容があとで変わったときなどに1箇所だけ修正すればすむようになります。
ひとによって違う部分もあるとおもいますが、わりと一般的な暗黙のマナーとして、(すべておおまかなもので厳密に守らなければいけないというようなものではない)
○ヘッダファイルはだいたいひとつのソースファイルに対し、ひとつ作成します。
ヘッダファイル名はソースファイル名と同じで、拡張子を.hにします。
○ヘッダファイルの先頭に以下のような2重インクルードを防ぐための#ifdefを定義するのが一般的です。
(HONYARARAはなんでもよいが他で使われていないことが保証されるもの。たとえばヘッダファイル名を使用)
--------------
#ifndef __HONYARARA_H__
#define __HONYARARA_H__
ここにヘッダの内容
#endif /* __HONYARARA_H__ */
--------------
同じヘッダを2回インクルードするとコンパイル時にすでに定義されています、というようなエラーになりますが、こうしておけばそれを回避できます。
○ヘッダファイルに#includeで別のヘッダをインクルードするのは[できるだけ]避けます。
もちろんそれが必要な場合もありますので禁止というわけではありません。
ヘッダにヘッダをインクルードすると、必要以上にそのヘッダを参照するソースが増えるため、たとえばあるヘッダを修正すると、本来その必要のないソースまで大量のソースを再コンパイルしてしまう羽目になりかねません。
質問者さんの立場はよくわかりませんが、これらはいまはよく意味がわからなくてもマナーとして癖にしておくとよいとおもいます。
No.2
- 回答日時:
aaa.c というように、単一ファイルで構成される
場合、インクルードファイルは、不要です。
aaa.c bbb.c ccc.c など、ソースファイルが複数
あるような場合、
共通する#define定義・外部変数の定義/extern 宣言
または、bbb.cに存在する関数をaaa.cで参照するよう
な場合の関数のextern宣言など、複数のソースファイ
ルで共通的な定義をする場合、インクルードファイル
を使用します。
下記URLが比較的わかりやすく書かれています。
「2.インクルード」を参照してください。
参考URL:http://www.orchid.co.jp/computer/cschool/clec10. …
No.1
- 回答日時:
ヘッダファイルは、最初からある物も含めてそのファイル中で使う変数や関数、クラスにどういうものがあるのかを記述してあります。
例えばa.ccというファイルの中で作ったクラスをb.ccというファイルで使うためには、そのクラスの名前やどのように呼び出す関数があるのかがわからないとb.ccというファイルを見ただけではわかりません。そこでそのクラスの呼出方等を記述した物がヘッダでありそれを参照することによって文法的に正しいかをチェックするわけです。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
関連するカテゴリからQ&Aを探す
おすすめ情報
- ・漫画をレンタルでお得に読める!
- ・一回も披露したことのない豆知識
- ・これ何て呼びますか
- ・チョコミントアイス
- ・初めて自分の家と他人の家が違う、と意識した時
- ・「これはヤバかったな」という遅刻エピソード
- ・これ何て呼びますか Part2
- ・許せない心理テスト
- ・この人頭いいなと思ったエピソード
- ・牛、豚、鶏、どれか一つ食べられなくなるとしたら?
- ・あなたの習慣について教えてください!!
- ・ハマっている「お菓子」を教えて!
- ・高校三年生の合唱祭で何を歌いましたか?
- ・【大喜利】【投稿~11/1】 存在しそうで存在しないモノマネ芸人の名前を教えてください
- ・好きなおでんの具材ドラフト会議しましょう
- ・餃子を食べるとき、何をつけますか?
- ・あなたの「必」の書き順を教えてください
- ・ギリギリ行けるお一人様のライン
- ・10代と話して驚いたこと
- ・家の中でのこだわりスペースはどこですか?
- ・つい集めてしまうものはなんですか?
- ・自分のセンスや笑いの好みに影響を受けた作品を教えて
- ・【お題】引っかけ問題(締め切り10月27日(日)23時)
- ・大人になっても苦手な食べ物、ありますか?
- ・14歳の自分に衝撃の事実を告げてください
- ・架空の映画のネタバレレビュー
- ・「お昼の放送」の思い出
- ・昨日見た夢を教えて下さい
- ・ちょっと先の未来クイズ第4問
- ・【大喜利】【投稿~10/21(月)】買ったばかりの自転車を分解してひと言
- ・メモのコツを教えてください!
- ・CDの保有枚数を教えてください
- ・ホテルを選ぶとき、これだけは譲れない条件TOP3は?
- ・家・車以外で、人生で一番奮発した買い物
- ・人生最悪の忘れ物
- ・【コナン30周年】嘘でしょ!?と思った○○周年を教えて【ハルヒ20周年】
- ・10秒目をつむったら…
- ・人生のプチ美学を教えてください!!
- ・あなたの習慣について教えてください!!
- ・都道府県穴埋めゲーム
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
C言語初心者の質問失礼します。
-
ファイル名の先頭にアンダース...
-
テキストファイルの最終行を削...
-
CSVファイルの入出力と計算
-
分割コンパイルの#defineについて
-
VB.NET ファイルをひとつにまと...
-
グローバル変数のよくない使い...
-
ASP .NETでファイル選択ダイア...
-
[VBScript]ファイルの入出力を...
-
unlinkしたファイルを元に戻す...
-
エクスプローラから開かれるWor...
-
csvファイルを開かずに文字を検...
-
CSVファイルへの保存の際、デー...
-
iniファイルに追記がしたいです。
-
FileOpen 関数で既にファイル...
-
fopenできる上限の変更
-
エクセルVBA Dir途中で止まる
-
SGファイルって何ですか?
-
Thunderbirdでemlファイルを開...
-
JARファイルの利点について
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
C言語初心者の質問失礼します。
-
ファイル名の先頭にアンダース...
-
csvファイルを開かずに文字を検...
-
テキストファイルの最終行を削...
-
VBに、Cのincludeのようなもの...
-
SGファイルって何ですか?
-
C言語のfopenについて教えてく...
-
分割コンパイルの#defineについて
-
アプリケーション終了時例外エ...
-
ドラッグアンドドロップでファ...
-
CSVファイルへの保存の際、デー...
-
ASP .NETでファイル選択ダイア...
-
大きいサイズのテキストファイ...
-
Javascript で INI の読み書き
-
グローバル変数のよくない使い...
-
fopenできる上限の変更
-
ハッシュの計算時間について
-
Excelマクロでの再読込み方法
-
UTL_FILEにて既存のExcelに追加...
-
ファイルの結合
おすすめ情報