0

我们试图在 Tandem X 系列机器上编译一个程序,但我们得到了形式的错误,“在 C 和/或 C++ 中初始化数据项的非法重复定义”。相同的代码在 aTandem S 系列机器上为我们成功编译。

我们有以下文件结构:

/---地址映射.h----/

#ifndef ADDRESSMAP // Header file macro
#define ADDRESSMAP  // Header file macro    
typedef map<long,char*,less<long> > gAddress;  data type
gAddress::iterator gAddressIterator;  // define iterator
gAddress gAddressMap;  // define variable    
#endif//ADDRESSMAP

/*file1.cpp:-> 使用地址映射的第一个文件 */

#include "AddressMap.h"   // include file

/*file2.cpp:-> 第二个文件也使用地址映射 */

#include "AddressMap.h"     // include file

问题

两个文件都已成功编译,但将它们链接在一起失败...

file1.o和file2.o中初始化数据项gAddressMap的非法重复定义

由于两个文件都需要访问这个变量,所以都包含了头文件;也许这是造成错误的原因。此外,它是现有代码,因此我们希望避免重大代码更改。特别是,我们希望保持相同的头文件和变量名。

我们如何解决这个错误?

串联细节:

  • X系列
  • 使用的链接器是 xld(nld 在本系列中不可用)
4

2 回答 2

4

每个编译单元——粗略地说,一个源文件和所有直接或间接#include写入其中的文件——都是单独编译的。因此,如果您将特定的标头包含在两个单独的文件中,它们都会编译声明

gAddress::iterator gAddressIterator;  // define iterator
gAddress gAddressMap;  // define variable    

因为这些没有被声明extern,所以它们构成了这些对象的定义。因此,每个包含标头的文件都包含每个对象的定义,并且每个对象文件都有自己的版本。C++ 允许对同一个对象进行多次声明,但在每个完整的程序中只能定义一个。因为你的每个模块都有一个 和 的定义gAddressMapgAddressIterator所以你不能形成一个将两者结合起来的符合程序。

解决方案有两个部分。首先,您必须确保头文件的声明不是定义。您可以通过声明它们来实现这一点extern

extern gAddress::iterator gAddressIterator;  // declare iterator
extern gAddress gAddressMap;  // declare variable

其次,您必须将实际定义放在某个地方,在您打算合并到一个程序中的所有文件中的一个文件中。如果有一个源文件包含用于初始化或以其他方式管理这些对象的函数,那么这将是一个很有希望的地方,但不是多个其他文件可能包含的头文件。

于 2017-01-12T15:43:16.870 回答
2

在我看来,你应该在头文件中用extern限定符声明你的全局变量,因为这个全局变量在多个 C 文件之间共享。

extern gAddress gAddressMap;  // define variable   
于 2017-01-12T15:28:43.783 回答