とっておきの「まかない飯」を教えて下さい!

いつもお世話になっています。
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を検索してみたのですが、
このような特殊な場合について記述されているものは
見つけられませんでした。
どなたか解決法又はヒントをご教示頂ければ
ありがたいです。
よろしくお願いします。

A 回答 (5件)

二重インクルードは防止できています。

ただし、あくまで1つのコンパイル単位の中での話です。エラー内容から察すると、2つ以上のソースファイルでaaa.hをインクルードしていますね?コンパイル時点ではエラーにはならずに複数のobjファイルが生成されますが、リンク時にエラーが発生します。これは、リンク実行時に関数waの定義が複数のモジュールで発見されるためです。

このようなエラーを防ぐため、通常、ヘッダファイルで関数の定義は行わず、その代わりに

extern int wa(int a, int b);

のように宣言だけを記述します。関数定義はどこかのソースファイルで1回だけ行います。
    • good
    • 0
この回答へのお礼

定義部分を別ファイルにすることにしました。
その結果、リンクエラーは解決できました。
ご教示ありがとうございました。

お礼日時:2003/07/25 14:38

#2、#4さんのご指摘どおりです。


インクルードファイルに関数定義を記述するのは好ましくありません。
通常は、関数定義ではなく関数プロトタイプ宣言を記述します。
関数定義は別のソース(wa.c)などに記述し、リンクしてください。
    • good
    • 0
この回答へのお礼

ご教示ありがとうございました。

お礼日時:2003/07/25 14:40

#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;
}
でもこれは普通じゃないです。
    • good
    • 1
この回答へのお礼

丁寧な解説を頂き、
エラー原因のメカニズムが良く分かりました。
最終的には、
普通でない方法は辞めることにし、
うまくビルド成功しました。
ご教示ありがとうございました。

お礼日時:2003/07/25 14:40

ここに書かれているソースでは#define AAAの前にスペースが無いですが、配信されてきたメールにはスペース(TAB?)がありました。


私の記憶では、#defineは先頭から始まっていなければならなかったという思います。このため AAAが定義されずに重複エラーとなったのではないでしょうか?
    • good
    • 0
この回答へのお礼

ご教示ありがとうございました。
スペースについては、特に問題ないようでした。

お礼日時:2003/07/25 14:38

ヘッダに関数の'定義'があるのがヘンです。


多くの場合リンク時にエラーとなるでしょう。
    • good
    • 0
この回答へのお礼

ご教示ありがとうございました。

お礼日時:2003/07/25 14:37

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています


おすすめ情報