13

他のいくつかのファイルで使用したい関数を含むutil.hファイルを定義しました。このヘッダーにはインクルードガードがありますが、2つの異なるファイルで使用すると、multiple definition of...エラーが発生します。私は何が間違っているのですか?

私はこれを読みましたが、これは変数の宣言/定義に関係しています。 この答えはより適切に思えますが、これをどのように修正できるかは私にはわかりません。

// util.h
// include lots of standard headers
#include ...

#ifndef UTIL_H
#define UTIL_H

using namespace std;
// multiple definition of `randarr(int, int, int)`
int* randarr(int size, int min, int max) {
    int *ret = new int[size];
    for (int i=0; i<size; i++)
            ret[i] = (int) (((double) rand() / RAND_MAX) * max) + min;
    return ret;
}
// no error
template<typename T> void printarr(T* v, int begin, int end) {
    for (int i=begin; i<end; i++)
    cout << v[i] << " ";
    cout << endl;
}
// multiple definition of `is_prime(int)`
bool is_prime(int n) {
    if (n == 2 || n == 3 || n == 5) return true;
    if (n <= 1 || (n&1) == 0) return false;

    for (int i = 3; i*i <= n; i += 2)
            if (n % i == 0) return false;

    return true;
}
#endif

// example.cpp
#include ...// lots of standard includes
#include "util.h"
void f() {
    randarr(...);
    printarr(...);
    is_prime(...);
    ...
}

// Main.cpp
#include "util.h"
int main() {

}
4

4 に答える 4

17

インクルードガードはエラーの原因ではありません。単一定義規則に違反しています。util.hは2つのソースファイルに含まれているため、各ソースファイルの前処理後に作成された変換ユニットには、各関数の定義が含まれ、複数定義エラーが発生します。

エラーを取り除くには、関数にマークを付けますinline

inline int* randarr(int size, int min, int max) {
  // ...
}

template<typename T> 
inline void printarr(T* v, int begin, int end) {
  // ...
}

inline bool is_prime(int n) {
  // ...
}
于 2012-10-19T20:11:52.180 に答える
14

コンパイラエラーではなく、リンカエラーが発生します。randarr()ファイルに関数を実装しましたutil.h。これは、コンパイラがとのそれぞれrandarr()でのコピーを確認することを意味します。リンカがこれらをリンクしようとすると、同じ関数の定義を複数持つことが許可されていないため、文句を言います。example.cppMain.cpp

2つの選択肢があります。

  • ヘッダーファイルのようにrandarr()宣言しますinline
  • の定義をファイルに移動randarr()util.cppます

同じ修正をに適用しis_prime()ます。

于 2012-10-19T20:11:51.370 に答える
4

ヘッダーファイルで関数を定義しました。つまり、これらの関数のコードはとの両方に含まれていexample.cppますMain.cpp。また、コードが2回生成されることも意味します。これが「複数定義」エラーの理由です。

関数を定義randarr()is_prime()、別ので1回だけ定義するutil.cppと、エラーはなくなります。

于 2012-10-19T20:13:03.080 に答える
0

ヘッダーには、関数のプロトタイプのみを含める必要があります。プロトタイプは関数を他のファイルに記述しますが、実装はしません。唯一の例外はテンプレートです。これは、各テンプレートの特殊化がコンパイル時に構築されるためです。

関数をヘッダーファイルに実装すると、リンカー時に関数の内容が複数回検出されるため、エラーが発生します。

randarrおよびの実装is_primeを別のファイルに移動し、util.hを次のように変換します。

#ifndef UTIL_H
#define UTIL_H

using namespace std;
int* randarr(int size, int min, int max);
template<typename T> void printarr(T* v, int begin, int end) {
    for (int i=begin; i<end; i++)
    cout << v[i] << " ";
    cout << endl;
}
bool is_prime(int n);
#endif
于 2012-10-19T20:11:48.547 に答える