- ベストアンサー
関数の実体定義にヘッダファイルの2重定義防止方法が効かない?
いつもお世話になっています。 MFCでCプログラミングをしています。 ヘッダファイルの2重定義防止のために、 ヘッダファイル全体を下記のように 囲みました。 <aaa.h> #ifndef AAA #define AAA #define PI 3.141592 void Func(); int wa(int a, int b){ return a+b; } #endif ビルドしたところ、 関数宣言(Func)や#define部分(PI)については、 2重定義が防止されているようなのですが、 関数の実体部分(関数wa)については、 2重定義防止機能が働かず、 ***.obj : error LNK2005: "int __cdecl wa(int a, int b)" は既に ***.obj で定義されています。 というリンクエラーが表示されます。 関数の種類や ヘッダファイル内の宣言の順番を いろいろ変えてみたのですが同じ結果でした。 ここで、このヘッダファイルの先頭に #pragma onceを使用すると このリンクエラーは回避されるのですが、 他コンパイラとの互換性の観点から、 #pragma once以外の方法で実現する必要があるので、 困っています。 URLを検索してみたのですが、 このような特殊な場合について記述されているものは 見つけられませんでした。 どなたか解決法又はヒントをご教示頂ければ ありがたいです。 よろしくお願いします。
- みんなの回答 (5)
- 専門家の回答
質問者が選んだベストアンサー
二重インクルードは防止できています。ただし、あくまで1つのコンパイル単位の中での話です。エラー内容から察すると、2つ以上のソースファイルでaaa.hをインクルードしていますね?コンパイル時点ではエラーにはならずに複数のobjファイルが生成されますが、リンク時にエラーが発生します。これは、リンク実行時に関数waの定義が複数のモジュールで発見されるためです。 このようなエラーを防ぐため、通常、ヘッダファイルで関数の定義は行わず、その代わりに extern int wa(int a, int b); のように宣言だけを記述します。関数定義はどこかのソースファイルで1回だけ行います。
その他の回答 (4)
- MovingWalk
- ベストアンサー率43% (2233/5098)
#2、#4さんのご指摘どおりです。 インクルードファイルに関数定義を記述するのは好ましくありません。 通常は、関数定義ではなく関数プロトタイプ宣言を記述します。 関数定義は別のソース(wa.c)などに記述し、リンクしてください。
お礼
ご教示ありがとうございました。
- bikkuri
- ベストアンサー率33% (23/68)
#2の方の通りかと思います。 aaa.hファイルが問題のヘッダーファイルとして、 ソースファイルがa.c, b.cの2つあるとすると a.cでは、 #inlucde "aaa.h" ...... b.cでも #include "aaa.h" ...... とされていると思います。 すると2つのソースから作成されるa.obj,b.objそれぞれに 関数waが定義されており、しかもグローバルなスコープです。 よって、リンク時にwaが2つあるのでエラーになっていると思います。 対処としても、#2の方と同じく 関数waはどこかのソースに実体を記述し、ヘッダーファイルに 関数のプロトタイプを記述するのが通常です。 どうしてもヘッダーファイルに関数の実体を記述したいのでしたら スコープをstaticにすればエラーを回避できるでしょう static int wa(int a, int b){ return a+b; } でもこれは普通じゃないです。
お礼
丁寧な解説を頂き、 エラー原因のメカニズムが良く分かりました。 最終的には、 普通でない方法は辞めることにし、 うまくビルド成功しました。 ご教示ありがとうございました。
- yatokesa
- ベストアンサー率40% (201/496)
ここに書かれているソースでは#define AAAの前にスペースが無いですが、配信されてきたメールにはスペース(TAB?)がありました。 私の記憶では、#defineは先頭から始まっていなければならなかったという思います。このため AAAが定義されずに重複エラーとなったのではないでしょうか?
お礼
ご教示ありがとうございました。 スペースについては、特に問題ないようでした。
- επιστημη(@episteme)
- ベストアンサー率46% (546/1184)
ヘッダに関数の'定義'があるのがヘンです。 多くの場合リンク時にエラーとなるでしょう。
お礼
ご教示ありがとうございました。
お礼
定義部分を別ファイルにすることにしました。 その結果、リンクエラーは解決できました。 ご教示ありがとうございました。