• 締切済み

ソースとヘッダの境界とは?

C/C++のプログラミングにおいて、これだけは絶対にソースファイル(.c,.cpp)書かなくてはならない!というものはあるのでしょうか? 仕事でプログラミングをしている時に、同僚から「その変数の定義はソースファイルに書かないとダメ」と言われました。 「その変数の定義」とは、メモリの物理アドレスへの割り付けを伴うもので、以下のようなものです。 #pragma section=~, IO=~, attr=~, locate=0xFECA0000 __io int piyo; /* 0xFECA0000 */ __io int hoge; /* 0xFECA0004 */ 特殊なコードで分かりにくく、申し訳ないのですが、簡単に言えば、「locate」で指定した物理アドレスから連続で変数を割り当てていくものです。 このコードをなぜヘッダではなく、「絶対に」ソースファイルに書かなくてはならないのかを尋ねましたが、明確な回答は得られませんでした。 私の認識としては、ソースファイルにAという処理を書くことと、Aの処理を書いたヘッダファイルをincludeすることとは、コンパイラにとっては全く同じことだと思ってます。 試しに、以下のソースを書いた「ヘッダ」ファイル”test.h”と「#include "test.h"」とだけ書いたソースファイル”test.c”を作成してビルドしたら、ちゃんと動く実行ファイルができました。 #include <stdio.h> int main(void) { printf( "Hello, World!\n" ); return 0; } 今回ご回答頂きたいのは、上記の物理アドレス割り付けのコードについてではなく、一般的な話として、これは「絶対に」ソースファイルに書かなきゃいけない!それは「絶対に」ヘッダファイルに書かなきゃいけない!とか言うものがあるのかどうか。あるとすれば、具体的にどのようなものなのかと言うことです。 何卒よろしくお願いいたします。

みんなの回答

  • riwity
  • ベストアンサー率58% (7/12)
回答No.11

クラス内にstaticやconstのつく変数があれば、その定義・初期化はソースファイルで行います。 // MyClass.h -------------------------- class MyClass{ static int sttcVal; const int cnstVal; }; // int MyClass::sttcVal= 0; // エラー // int MyClass::cnstVal= 0; // エラー --------------------------------------- // MyClass.cpp ------------------------ int MyClass::sttcVal= 0; int MyClass::cnstVal= 0; --------------------------------------- この定義・初期化はヘッダではエラーになるはずです。 (ただしconstについてはあまり使わないので自信はありません…。)

  • jacta
  • ベストアンサー率26% (845/3158)
回答No.10

#4です。 回答者の中にも変なことをいう人もいるようなので、もう少し詳しく書きます。 まず、今回の場合に限った話をします。 処理系不明なので正確なことはいえませんが... > #pragma section=~, IO=~, attr=~, locate=0xFECA0000 > __io int piyo; /* 0xFECA0000 */ > __io int hoge; /* 0xFECA0004 */ これは組込み向けの処理系にはよくある拡張機能を使った書き方かと思います。 この場合、I/Oポートの名前を定義することが目的ですので、複数の翻訳単位でそれらの名前を使用するつもりであれば、ヘッダファイルに記述するのが一般的なやり方です。 もし、お使いの処理系が、piyoやhogeを外部結合にしてしまうのであれば、staticを付けて内部結合にすればよいだけの話です。特定の翻訳単位のみで定義するようにし、他の翻訳単位では外部宣言にすることも可能ですが、I/Oポートの一覧を二重にメンテナンスしなければならなくなるだけで、あまりメリットはありません。 そうではなく、I/Oポートの制御を単一の翻訳単位に閉じ込める(すなわち、他の翻訳単位からはI/Oを直接触らせない)という設計であるなら、誤用を防ぐ意味でヘッダファイルに書かない方が望ましいでしょう。 次に一般的な話としてですが、ヘッダファイルでは関数やオブジェクトの外部宣言とマクロや型の定義を行い、関数やオブジェクトの定義は(ヘッダファイルではない)ソースファイルで行うのが基本ですが、決して「絶対」のルールではありません。 なぜなら、常にそうではないからです。 具体的な例を挙げます。 もっとも分かりやすいのは、インライン関数とテンプレートです。これらはヘッダファイルに定義を書くことになります。 今回のように、処理系特有の事情で各翻訳単位ごとに定義を行った方がよい場合もあります。 あるいはハードウェア的な事情から、同じ内容の関数やオブジェクトの実体を複数持たせた方がよい場合もレアケースですが存在します。 したがって、遭遇頻度がどうであれ、例外的な事例がある以上、「絶対に」ソースファイルに書かなくてはならないということにはなりません。

  • bug_bug
  • ベストアンサー率78% (36/46)
回答No.9

コンパイル可能/不可能が記述のルールではありません. 試しに行ったテストは「たまたま」コンパイルエラーが出なかっただけで, 複数のモジュールから"test.h"をインクルードすれば簡単に多重定義のエラーが出ます. これは.hとファイル名が付いているだけで, 本来のヘッダファイルが担うべき役割を果たしていません. 先に回答ですが, .cや.cppファイルには実装を記述します. そして.hファイルには外部のモジュールから利用する為のインターフェイス仕様(使い方)を記述します. 以上が可読性・メンテナンス性に富んだ記述のある意味「絶対的」なルールです. 変数や関数の宣言はどっち, 構造体定義やマクロの記述はどっちと明言できません. 例えば, .cファイル内で使用している構造体について, 外部モジュールも知っていなければならないのであれば.hファイルで公開する必要がありますが, 必要ないのであれば.cファイル内に記載し公開させません. ちなみにサンプルの記述は変数の定義を行っていますので, .cファイルに記述しなければなりません. .hファイルに記述してしまうと, 複数ファイルからインクルードされた場合, 簡単に多重定義のエラーとなってしまいます. (私であれば"絶対に"と指導する内容です. #pragma ~ の内容を考慮する以前の問題) ポイントは複数のモジュールから.hファイルがインクルードされる事を考慮しているか否かです. 作成したモジュール(.cファイル)の機能を利用する為に, 外部から呼び出す為のインターフェイス(入出力仕様)を明記してあるのが.hファイルです.

  • titokani
  • ベストアンサー率19% (341/1726)
回答No.8

同僚の方も、「絶対に」とは言っていないように見えますが・・・。 「なるべく」書いたほうがよい、という話ならいっぱいありますね。 分割コンパイルをしていると、「なるべく」ソースに書いたほうがいい記述はあります。 しかし、これとて#define,#ifdefなんかを使えばヘッダファイルに書くことも可能です。 そんなわけで、「絶対に」という話はありません。同僚の方も、「なるべく」という意味で言ったのではないでしょうか?

回答No.7

別に、絶対にヘッダーファイルに書かなければならないというものは、言語規約的にはありません。矛盾がなければコンパイルは通るし、問題なく動作することも多いでしょう。 ただ、それと「コンパイル結果がプログラマの意図した通りであるか」は別のことです。 たとえば、ヘッダーファイルで変数の実体を定義してしまうと、そのヘッダーファイルをインクルードした回数分、変数が存在することになります。言語仕様上は、同一モジュール内で重複しなければ問題はないので、エラーが出ないようにすることは可能です。実際に変数を使用するのが1つのモジュールだけであれば、動作に影響することもないでしょう。しかし、同名の変数を複数モジュールに独立して持たせることを、プログラマが意図しているかというと、おそらく違うでしょう(意図している場合ももちろんありますが、それは「理解して行っている」ので今回の話からは外します) その場では問題なく動作していても、後に追加変更などで問題が出ることがあります。同名の変数だから、同じものであるとプログラマが誤解してしまうと、複数モジュールで共有しているつもりの変数が、実はモジュールごとに独立してるといったことが起こります。それが滅多に内容が変更されない変数であった場合は、きちんとチェックしないと正しく動作しているように見えるかもしれません。別のモジュールで変数の値を変更しても、他のモジュールでは変数の値が変化しないので、原因不明のバグに悩まされるでしょう。勘がいい人なら、変数のアドレスを確認して違うものと気づくかもしれませんが、同じものと思い込んでいると、その原因に気づくのは結構難しいです。

  • ricardo_
  • ベストアンサー率19% (14/72)
回答No.6

 私もここに時々質問している身で偉いことは言えないのですが、次のように考えています。  拡張子は、その使用目的が分かるように区別するために使っています。  エディタに、色分け機能が付いています。C言語のキーワードやコメント によって色を変える機能です。  拡張子の区別は、その色分けと同じです。  その意味では拡張子がTXTでもいい訳ですが、エディタが拡張子を見てタブの文字数を設定したり、言語による色分け機能などを行う訳ですから世間一般と逆らってもメリットが無い。  Cコンパイラにファイル名を"A"と入力すれば、"A.c"ファイルを探し"A.obj"ファイルを出力する仕様になっているかも知れない。  その場合"A.txt"では、コンパイル出来ない。  ヘッダファイルには、それだけでは命令にならない物が書いてあります。  ファイルによっては、HにするかCにするか微妙な物が有ると思います。  それは、個々の人の判断によると思います。  私はプロトタイプだけを独立してファイルにしています。  それだけを見ると、標準関数のヘッダのような物です。  しかし拡張子”C”で書かれたファイルの一部を抜き出した物ですから、拡張子は”C”にしています。  あなたの先輩も、Cファイルの一部分を独立させた物という位置付けで考えたのでは無いでしょうか。

  • Interest
  • ベストアンサー率31% (207/659)
回答No.5

> 私の認識としては、ソースファイルにAという処理を書くことと、 > Aの処理を書いたヘッダファイルをincludeすることとは、 > コンパイラにとっては全く同じことだと思ってます。 私も同じ認識です。 それでも変数の定義をソースファイルに記述するのは、その職場/プロジェクト毎のコーディング規約によるものだと思います。おそらく、次のような考えがあって「ヘッダファイルに書くな、ソースファイルに書け」と言っているのではないでしょうか。 理由1:ヘッダファイルはインタフェースとして他人に見せるものだから、実体を書くべきではない。(特にC++では) 理由2:物理アドレスの割り付けを変更したとき、そのヘッダファイルをインクルードしている全てのソースコードを再コンパイルすることになるので無駄が多すぎる。 私は組み込み系の仕事をしていますが、例えばルネサスの開発環境ではCPU毎のヘッダファイルにレジスタにアクセスするためのポインタとアドレスの定義がずらずら書かれています。ですから絶対にダメということはないと思いますよ。

  • jacta
  • ベストアンサー率26% (845/3158)
回答No.4

まず、「ヘッダ」と「ヘッダファイル」の違いは分かりますか? 「ヘッダ」は処理系が提供するものなので、ユーザーが書くものではありません。 次に、「ヘッダファイル」というのはソースファイルの一種です。 規格上はどちらに書いてもかまいません。したがって、「絶対に」ソースファイルに書かなきゃいけない! などというものはありません。ただし、単一定義規則等の制約はあります。 もちろん、職場のコーディング規約等で「絶対に」ソースファイルに書けということが決められている可能性があります。しかし、そのようなローカルルールは、私を含めた回答者が知るはずがありません。

  • asuncion
  • ベストアンサー率33% (2127/6289)
回答No.3

1つのヘッダーファイルを複数のソースファイルから インクルードする、という状況があり得ます。 それをふまえて、関数の実体はヘッダーファイルに書かない、 という措置がおそらく必要でありましょう。 他にも、ヘッダーファイルに書いてはいけない (もしくは書かないほうがよい)内容があるかもしれません。

  • don_go
  • ベストアンサー率31% (336/1059)
回答No.2

コーディング規約がどうなっているかにもよりますが 複数のソースで共有使用しているインクルードファイルを 変更すると、関連しているソースを再コンパイルする必要 が有ります。 特定のソースでしか使用しない事が分かっている様な場合 には、ヘッダファイルとせずに直接ソースファイルに記述 する事があります。

関連するQ&A

専門家に質問してみよう