質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.50%

  • VC++

    136questions

    VC++ (Visual C++) とは、Microsoft製のC++のための統合開発環境です。

ヘッダファイルでの変数の定義について(VC++)

解決済

回答 1

投稿

  • 評価
  • クリップ 1
  • VIEW 2,603

ryo.robolabo

score 8

プログラミング初心者です。
くだらない質問だったらごめんなさい。

環境はWindowsのVisual C++(2015 RC)です。

分割コンパイルのヘッダファイルについてなのですが、インターネットで調べるとヘッダファイルで変数や関数の定義はするな、と書いてありました。ですが、#ifndef-#define-#endif や #pragma once を使えば二重定義は回避できるとも書いてありました。

そこで、新しく作ったファイルにtest.hというヘッダファイルを追加して、そこに#pragma onceと書いたうえで変数の定義をしたところ問題なく実行できてしまったのですが、これは#pragma onceさえ使えばヘッダファイル内で定義をしても問題ないということですか?それとも気づかないところで何か問題が起こっているのでしょうか。

また、構造体の要素数がかなり多くなりそうなので別のファイルに定義したくて分割コンパイルについて調べたので、別のファイルで定義する良い方法が他にありましたら教えていただけるとありがたいです。

よろしくお願いします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+8

こんにちは。

ヘッダで変数や関数の実体を定義するのは結構困ったことが起きます。
ヘッダで他で定義された変数や関数を使う旨宣言するのは問題ありません。

この辺、宣言とか定義とか用語が分かりにくいので、「実体定義」と「使用宣言」で使い分けてみます。
(規格書の使い方とたぶん一致していないですが...)

実体定義:

下記はどちらとも実体を定義しています。ヘッダで実体を定義するのはやめるべきです。

int  foo;
void bar()
{
   :
}

使用宣言:

下記はどちらも使うことを宣言しています。ヘッダで行う主な作業の1つです。

extern int foo;
void bar();

実体をヘッダで定義すると下記問題が発生します。

通常ヘッダは複数のcppファイルからインクルードされます。
例えば、main.cppやsub.cppからfoo.hをインクルードし、2つとものcppを使って1つのexeを作るようなことを良く行います。
この時、foo.hで「実体定義」していると、main.cppとsub.cppの両方でその実体が定義されてしまいます。結果、多重定義エラーになってしまいます。

しかし、例えば、実体定義はmain.cppで行い、foo.hでは使用宣言のみを行えば、多重定義エラーを避けることができるのです。

インクルード・ガード

以上の話は、#pragma onceの動作とは無関係です。
#pragma onceは同じヘッダが同じcppから幾度もインクルードされないようにする仕組みです。
例えば、<iostream>は結構あちこちからインクルードすると思います。cppから直接インクルードしたり、そのcppがインクルードしているヘッダからインクルードしたりしてしまいます。
すると何度も同じものがインクルードされるため、例えば#define FOO xxxなどの定義が多重定義になってしまいます。それを避けるのが#pragma once等のインクルード・ガードです。
1つのcppから一度インクルードしたヘッダを、同じcppからヘッダ等を経由して再度インクルードしても中身をコンパイルしない仕組みです。

ついでにコンパイル単位について補足

Visual Studioのソリューション・エクスプローラのSource Filesに登録した1つ1つのソース・ファイルが事実上「コンパイル単位」となります。
これらのソースを1つ1つコンパイルして、objファイルを作り、最後にリンクしてexeファイルを作ります。
このソースを1つコンパイルすることを指して「コンパイル単位」と呼びます。

1つのコンパイル単位の中で、同じヘッダが複数回インクルードされないようにする仕組みがインクルード・ガードです。
複数のコンパイル単位の中で、同じ実体が複数回定義されないようにするために、ヘッダで実体定義しないようにします。


【追記】

また、構造体の要素数がかなり多くなりそうなので別のファイルに定義したくて分割コンパイルについて調べたので、別のファイルで定義する良い方法が他にありましたら教えていただけるとありがたいです。

1つの構造体を複数のファイルに渡って定義することも不可能ではないですが、あまり行わないです。
たった1つの構造体の定義に例えば1,000行も使うような場合は、別の構造体に分割した方が良いと思います。
例えば下記のような手法を使えば、自然に分割できるケースが多いです。

struct SubStructA
{
    :
};
struct SubStructB
{
    :
};
struct SubStructC
{
    :
};

struct BigStruct
{
    SubStructA  mSubStructA;
    SubStructB  mSubStructB;
    SubStructC  mSubStructC;
};

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/03/30 21:25

    回答ありがとうございます。返事が遅くなり申し訳ありません...

    インクルードガードは同じcppファイル内で何度もインクルードしないようにするものなのですね。勘違いをしていたようです。

    勉強になりました^^

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.50%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • VC++

    136questions

    VC++ (Visual C++) とは、Microsoft製のC++のための統合開発環境です。