包括不工作的警卫

xst*_*xst 6 c++ compiler-errors include

我已经定义了一个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
Run Code Online (Sandbox Code Playgroud)
// example.cpp
#include ...// lots of standard includes
#include "util.h"
void f() {
    randarr(...);
    printarr(...);
    is_prime(...);
    ...
}
Run Code Online (Sandbox Code Playgroud)
// Main.cpp
#include "util.h"
int main() {

}
Run Code Online (Sandbox Code Playgroud)

Gre*_*ill 10

您收到链接器错误,而不是编译器错误.你已经实现的功能randarr()在你的util.h文件,这意味着编译器看到的副本randarr()在每个example.cppMain.cpp.当链接器将这些链接在一起时,它会抱怨,因为你不允许有多个相同函数的定义.

你有两个选择:

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

应用相同的修复程序is_prime().


Pra*_*ian 9

包括警卫不是错误的原因; 你违反了一个定义规则.由于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) {
  // ...
}
Run Code Online (Sandbox Code Playgroud)

  • 当然,警卫在那里是为了防止第二个定义,他们是不是允许多个包含?什么'内联'甚至可以解决这个问题? (4认同)
  • @Troyseph是的,包括警卫防止多个包含......*在单个翻译单元*(大致是.cpp文件).如果您在多个cpp文件中包含标头,它们不会防止任何事情,在这种情况下,您将遇到多个定义的链接器错误,因为您违反了ODR(ODR违规*不需要诊断*,因此实现不是'甚至需要检测和错误输出).`inline`告诉链接器将多个定义视为单个定义并选择一个定义,从而避免错误. (3认同)