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

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

新規登録して質問してみよう
ただいま回答率
85.50%

Q&A

解決済

1回答

9977閲覧

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

ryo.robolabo

総合スコア16

2グッド

1クリップ

投稿2016/03/23 13:32

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

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

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

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

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

よろしくお願いします。

Chironian, pinnkoro👍を押しています

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

こんにちは。

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

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

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

C++

1int foo; 2void bar() 3{ 4 : 5}

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

C++

1extern int foo; 2void 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行も使うような場合は、別の構造体に分割した方が良いと思います。
例えば下記のような手法を使えば、自然に分割できるケースが多いです。

C++

1struct SubStructA 2{ 3 : 4}; 5struct SubStructB 6{ 7 : 8}; 9struct SubStructC 10{ 11 : 12}; 13 14struct BigStruct 15{ 16 SubStructA mSubStructA; 17 SubStructB mSubStructB; 18 SubStructC mSubStructC; 19};

投稿2016/03/23 14:03

編集2016/03/23 14:22
Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ryo.robolabo

2016/03/30 12:25

回答ありがとうございます。返事が遅くなり申し訳ありません... インクルードガードは同じcppファイル内で何度もインクルードしないようにするものなのですね。勘違いをしていたようです。 勉強になりました^^
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問