如何避免链接器错误

时间:2012-12-31 10:24:01

标签: c++ namespaces linker-errors

在General.h内部

#ifndef GENERAL
#define GENERAL
namespace counternamespace{
    int upperbound;
    int lowerbound;
}
#endif

Inside Analyzer.h

#ifndef ANALYZER
#define ANALYZER
#include"General.h"

class Analyzer
{
public :
     int var ;
     int func();
};
#endif

Inside Test.h

#ifndef TEST
#define TEST
#include"Analyzer.h" //Error
class Test2
{
public:
    Test2(void);

public:
    ~Test2(void);
};
#endif

在上面的代码中,我没有在Test.h内添加Analyzer,一切正常。但在添加后显示以下链接器错误。

1>Test2.obj : error LNK2005: "int counternamespace::lowerbound" (?lowerbound@counternamespace@@3HA) already defined in Analyzer.obj
2>Test2.obj : error LNK2005: "int counternamespace::upperbound" (?upperbound@counternamespace@@3HA) already defined in Analyzer.obj

我添加了#ifndef / #endif。然后我在做错误的地方?有人可以告诉我吗?

3 个答案:

答案 0 :(得分:2)

是的,Alok是对的。你可能有Analyser.cpp和Test2.cpp,两者都是不同的编译单元。当你打电话

g++ Analyser.cpp Test2.cpp

编译器实际上分别生成Analyser.obj和Test2.obj并将它们链接在一起。 当编译器尝试将Analyser.obj和Test2.obj链接在一起时,它意识到Test2.obj中的两个变量也存在于Analyser.obj中。

您的#define指令不起作用,因为它们仅存在于单个编译单元中,因此General.h包含两者在Analyser.obj和Test2.obj中。

为避免此类重复,the solution is wrapping your namespace variables附带一个函数。它是这样的:

在General.h内部

#ifndef GENERAL
#define GENERAL
namespace counternamespace{
    int& upperbound();
    int& lowerbound();
}
#endif

在General.cpp内部

#include "General.h"
namespace counternamespace{
  int& upperbound(){static int local; return local;}
  int& lowerbound(){static int local; return local;}
}

所以你现在可以说

counternamespace::upperbound()=3;
counternamespace::lowerbound()=1;

这意味着和你说的一样

counternamespace::upperbound = 3;
counternamespace::lowerbound = 1;

不用担心,编译器会优化掉函数调用,因此也没有开销。

答案 1 :(得分:1)

您不应在头文件中定义任何变量 在每个翻译单元中创建变量的副本当您将头文件包含在其他文件中时,会违反一个定义规则并导致链接错误。

答案 2 :(得分:1)

Inside General.h

#ifndef GENERAL
#define GENERAL
namespace counternamespace{
    extern int upperbound;
    extern int lowerbound;
}
#endif

Inside General.cpp

#include"General.h"
using namespace counternamespace ;
int counternamepace::upperbound = 12;
int counternamepace::lowerbound = 12;

然后做任何需要的事情。