13

我已经定义了一个 util.h 文件,其中包含我想在其他几个不同文件中使用的函数。这个头文件有一个包含保护,但是当我在两个不同的文件中使用它时,我得到一个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

你有两个选择:

  • 在头文件randarr()中声明inline
  • 将定义移动randarr()util.cpp文件中

is_prime().

于 2012-10-19T20:11:51.370 回答
4

您在头文件中定义了函数。这意味着,这些函数的代码都包含在example.cpp和 中Main.cpp。这也意味着代码将被生成两次。这就是“多重定义”错误的原因。

当您定义函数randarr()并且is_prime()仅在单独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 回答