• 締切済み

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

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% (2126/6286)
回答No.3

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

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

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

関連するQ&A

  • C++のヘッダーについて

    C++のプログラミングをしています そこで出てきた問題なのですが・・・ class Aのヘッダファイルa.hをほかのcppファイルにインクルードすると、 error C4430: 型指定子がありません - int と仮定しました。メモ: C++ は int を既定値としてサポートしていません error C2146: 構文エラー : ';' が、識別子 'test' の前に必要です。 とほかのヘッダファイルでコンパイルエラーがでます ヘッダファイルをインクルードしたときのみこのエラーがでて困っています。 解決法や、ヒントになりそうな事例を知りませんでしょうか?

  • C言語のヘッダファイルの使い方

    ヘッダファイルの使い方について質問です。 ソースファイルA、ソースファイルBで共有して使用したい変数がある場合、 Aでは「int a」と宣言し、Bでは「extern int a」と宣言すれば 同じ変数を共有出来ると認識しています。 それをヘッダファイルへ記述しておきたい場合にはどのように 宣言しておけば良いのでしょうか? ヘッダファイルに「int a」と宣言した場合は両方のソースファイルで includeした時に多重定義でエラーとなります。 では「extern int a」と宣言しておいて、両方のソースファイルで includeするのが正しいのでしょうか? 初歩的な質問で申し訳ないですが、有識者の方、教えてください。

  • ヘッダファイルとソースファイルについて

    今までは、Webプログラミングを行っていたのですが、 最近になって、C++の仕事を請け負いましたので、 C++を勉強しつつ、プログラムをしていたのですが、 Webプログラムとの違いに悩んでいる部分があります。 それは、ヘッダファイルとソースファイルの関係についてです。 ほかのファイルから、インクルードされたヘッダファイルが、 読み込まれるというのは納得がいくのですが、 そのヘッダファイルに関連付け(?)られたソースファイルも、 一緒に読み込まれるという理由がわかりません。 ヘッダファイルでソースファイルを読んでいるような記述もないような感じなので、とても疑問に思っております。 なぜ、ヘッダファイルをインクルードしただけで、付属のソースファイルも読み込まれるのでしょうか?

  • C言語でヘッダファイルにグローバル変数を宣言する

    main.hに static int a; と記述し、main.cで #include "main.h" [省略] a=10; のように使用して、-Wallをつけてコンパイルすると、main.cで使用しているにも関わらず、 'a' defined but not used という警告が表示されます。 同様に、関数においても、ヘッダファイルでstaticをつけると ‘~’ declared ‘static’ but never defined と警告されます。 静的グローバル変数などは、ソースファイル内で宣言しなければいけないのでしょうか?ヘッダファイル内で宣言しても警告が出ないような方法はありますか?

  • ヘッダファイルの2重のインクルードについて

    ある書物に「ヘッダファイルを複数回インクルードすると、それを”再定義”することによるエラーになる」と書いてありますたが、以下のようなヘッダファイルを作りそれを数回インクルードしても何ら異状が無くコンパイルできました。 math.h→ヘッダファイル名 #define max(a,b)  ((a)>(b)?(a):(b))→ヘッダファイルの内容 c ファイル #include<stdio.h> #include"math.h"←複数回インクルード #include"math.h"←複数回インクルード int main(void){ int x=1,y=2; printf("max(x,y)=%d\n",max(x,y)); return 0; } 環境としては、RedHat Linuxでviです。 何ゆえ、エラーにならないのか良く解りません。 宜しくお願いします。

  • Cソースにホスト変数を宣言したヘッダをインクルード方法

    C言語ソースにホスト変数を宣言したヘッダをインクルードする記述を教えてください。下記の記述をしたのですが、エラーになります。 EXEC SQL INCLUDE SQLCA; EXEC SQL BEGIN DECLARE SECTION; #include "../host_header.h" EXEC SQL END DECLARE SECTION;

  • linuxにおけるCの自作ヘッダファイル

    現在C言語のしっかりと学ばなかった部分を学習したいと思い、自作ヘッダファイルの作成を勉強しています。 そこで、書籍のその章を一通り読んだあと、自分で簡単なものを作成してみましたが、エラーが出てうまくいきません。 どうしてかわかる方いたら教えてください。 コード *****main.c***** #include "print.h" int main(void) { print(); return 0; } *****print.c***** #include <stdio.h> void print(void) { printf("test\n"); } *****print.h***** extern void print(void); エラー /tmp/ccH551c1.o: In function `main': /home/ユーザ名/Documents/StudyC/main.c:5: undefined reference to `print' collect2: ld returned 1 exit status CentOS6.6にて端末上での実行です。 自分の解釈では、""でincludeすることでカレントディレクトリから目的のヘッダファイルを見つけ出してインクルードする、また、ヘッダファイル内でexternすることによってprint.cから目的の関数を定義しているので、main.cでは問題なく使えると思っています。 しかし、エラーではprint()が定義されていないと出るのでまったくわかりません・・・。

  • JSPでCのようにヘッダーファイルをインクルード

    JSPでCのようにヘッダーファイルをインクルード お世話になります。 JSPでウェブページを作成しています。 ページ読み込み部分で前のページからPOSTされた情報に対して、 条件式を使い「真」ならそのページを表示、 偽の場合にはresponse.sendRedirect("URL");で別ページへジャンプをさせようと考えています。 その際に条件の判定に定数を使用したいのですが、 その定数は他のページでも使用する場合があるため、 C言語のヘッダーファイルのように、 別ファイルを用意して使い回しをしたいのですが… //test.h----------------------------- #pragma once const int CHECK_NUM = 15; //----------------------------------- //test.c #include <stdio.h> #include "test.h" int main(){ int n = 10; if(n < CHECK_NUM){ //真 } else{ //偽 } return 0; } このようにすればC言語では外部にかかれた定数を使用することができると思うのですが JSP,JAVAともに未経験のため詰まっています。(目下勉強中です) JSPで同様のことをするにはどのようにしたらよいのか教えていただきたいです。 質問をするにあたり情報の不足などがあるかもしれません。 その際にはお手数ですが、解答にてご指摘いただけると助かります。 宜しくお願い致します。

    • ベストアンサー
    • Java
  • C言語のヘッダーファイルの意味と使い方

    現在、C言語を学習ちゅうです。以下のヘッダーファイルの意味と使い方、後、読み方も教えて下さい。 #include <stdio.h> #include <stdlib.h> #include <conio.h> #include <tchar.h> #include <ctype.h> #include <string.h> 後、カウンター変数の意味と使い方も知りたいです。

  • ヘッダファイルの有効範囲

    現在OpenGLを使ったプログラムを作っていて, hoge.hというヘッダファイルで #include <GL/glut.h> piyo.hというヘッダファイルには #include "hoge.h" そしてさらにhogehoge.hというヘッダファイルに #include "piyo.h" として, hogehoge.cppのソースファイルにて #include "hogehoge.h"してOpenGLの関数を使おうとしたら エラーが出ました. hogehoge.cppでhogehoge.hをインクルード →hogehoge.hでpiyo.hをインクルード →piyo.hでhoge.hをインクルード →hoge.hでGL/glut.hをインクルード というように,橋渡し的にインクルードはできないのでしょうか? これはこのような仕様なのでしょうか? それとも他に誤りがある可能性があるのでしょうか… 非常に困っております. ご回答お待ちしております.

専門家に質問してみよう