C++ 与常量char*[]声明关联的重复符号错误

C++ 与常量char*[]声明关联的重复符号错误,c++,linker,C++,Linker,当我尝试用g++4.2.1进行编译时,我希望能够帮助诊断我收到的重复符号错误的来源 具体错误是 ld: duplicate symbol _SOCIODEM_FILENAMES in /var/folders/c+/c+eq1Qz1Feye7vxs5mQOUE+++TI/-Tmp-//ccP3yVgF.o and /var/folders/c+/c+eq1Qz1Feye7vxs5mQOUE+++TI/-Tmp-//cc1NqtRL.o collect2: ld returned 1 exit

当我尝试用g++4.2.1进行编译时,我希望能够帮助诊断我收到的重复符号错误的来源

具体错误是

ld: duplicate symbol _SOCIODEM_FILENAMES in /var/folders/c+/c+eq1Qz1Feye7vxs5mQOUE+++TI/-Tmp-//ccP3yVgF.o and /var/folders/c+/c+eq1Qz1Feye7vxs5mQOUE+++TI/-Tmp-//cc1NqtRL.o 
collect2: ld returned 1 exit status
仅当我将此声明包含在名为
Parameters.h的文件中时,才会发生错误:

// Parameters.h

#ifndef PARAMETERS_H
#define PARAMETERS_H

// ...[code snipped]...
const int NUM_SOCIODEM_FILES = 5;
const char * SOCIODEM_FILENAMES[ NUM_SOCIODEM_FILES ] = { "LSPAN_PDF.txt", 
     "FLEDGE_PDF.txt", 
     "PAIR_PDF.txt", 
     "BIRTH_AGE_PDF.txt",  
     "SPLIT_PDF.txt"  };
// ...[code snipped]...
#endif
我已经搜索了所有文件,这是唯一声明
socialdem\u文件名的地方。当我注释掉声明时,“复制符号”错误消失了

我不熟悉链接器错误(如果是这样的话),希望您能帮助我解决这个问题。我所有的头文件都有
#ifndef…#define…#endif
包装器。我的编译命令是

g++ -o a.out -I /Applications/boost_1_42_0/ Host.cpp Simulation.cpp main.cpp Rdraws.cpp
提前谢谢


解决方案摘要

我现在在参数中有了。h:

const char * const SOCIODEM_FILENAMES[ NUM_SOCIODEM_FILES ] = { "LSPAN_PDF.txt", 
                 "FLEDGE_PDF.txt", 
                 "PAIR_PDF.txt", 
                 "BIRTH_AGE_PDF.txt",  
                 "SPLIT_PDF.txt"  };

Parameters.h中的所有其他定义和声明保持不变。Andrey和其他评论者总结了一种使用
extern
的替代方法,这对我来说是过分的。

头保护(
\ifndef..\endif
包装器)只是防止您在单个源文件中多次包含相同的头。您仍然可以有多个包含该头的源文件,每个源文件将分别声明该符号。由于它们都具有相同的名称,因此将这些源链接在一起将导致符号名称冲突。您可能希望在源文件而不是头文件中声明符号

问题是您正在头文件中放置定义。如果您将该文件包含在多个编译单元(.cpp文件)中,则实际上您将创建多个定义,并且在链接时您将收到该错误

您需要将这两个定义都放在.cpp文件中,并且只在头文件中放一个声明:

extern const int NUM_SOCIODEM_FILES;
extern const char * SOCIODEM_FILENAMES[];

很可能,您正在将此文件包含在多个源文件中。问题在于,每次包含都会导致名为
socialdem\u FILENAMES
的变量的单独定义。包括防护装置对此没有帮助。在单个编译单元中包含多个声明;它们不会阻止跨多个编译单元的多个定义

您需要做的是在头文件中将这些变量声明为
extern
,然后在一个源文件中定义它们。e、 g

// Parameters.h

#ifndef PARAMETERS_H
#define PARAMETERS_H

// ...[code snipped]...
extern const int NUM_SOCIODEM_FILES;
extern const char * SOCIODEM_FILENAMES[];
// ...[code snipped]...
#endif
然后:

// Parameters.cpp (or some other source file)

const int NUM_SOCIODEM_FILES = 5;    
const char * SOCIODEM_FILENAMES[ NUM_SOCIODEM_FILES ] = { "LSPAN_PDF.txt", 
                 "FLEDGE_PDF.txt", 
                 "PAIR_PDF.txt", 
                 "BIRTH_AGE_PDF.txt",  
                 "SPLIT_PDF.txt"  };

对于
int
您可以不这样做,因为它是一个常量整数,因此编译器可以将其视为编译时常量,它甚至永远不会出现在编译后的代码中。但是,
char*
不能这样处理,因此必须只有一个定义(在C++中称为“一个定义规则”)。

正如其他人所建议的,一种方法是将
NUM\u SOCIODEM\u文件
SOCIODEM\u文件名
声明为
extern
,并在外部文件中定义一次。另一种方法是将它们声明为
静态
——这会导致它们在包含标头的每个对象文件中重复,但不会创建错误,因为该定义是该对象文件的专用定义。您选择哪个选项完全取决于您自己的喜好。

由于某些原因,迄今为止,没有一个答案能够解释整数
NUM\u socialdem\u文件
object和数组
socialdem\u文件名
object之间的差异。后者触发链接器错误的原因已经解释过了:因为您将头文件包含到多个实现文件中。然而,前者链接没有任何问题(因为
NUM\u socialdem\u文件
声明确实没有问题)。为什么?

原因是您的
NUM\u socialdem\u FILES
对象被声明为
const
。在C++中,const对象默认有内部链接,这意味着即使在多个实现文件中定义它们也不会引起链接问题。换句话说,在C++中,你的<代码> NothSooCoDeMyFrase相当于

static const int NUM_SOCIODEM_FILES = 5; /* internal linkage */
这就是为什么它不会导致任何链接问题

同时,您的
socialdem_文件名
并没有声明为常量,这就是它默认获得外部链接并最终导致链接器错误的原因。但是,如果您将您的
socialdem\u文件名也声明为
const
,问题就会消失

const char * const SOCIODEM_FILENAMES[ NUM_SOCIODEM_FILES ] = {
  ...
注意额外的
const
在声明中的位置。如果您只是添加额外的
const
,而其他内容保持不变(即在头文件中保留定义If
socialdem_FILENAMES
),则即使您将头文件包含到多个翻译单元中,链接器也不会报告错误

不过,这不是一种推荐的方法,因为这样您将提供
SOCIODEM_文件名
内部链接,并最终在每个翻译单元中提供
SOCIODEM_文件名
数组的独立副本-这可能很好,但意义不大。因此,对于数组,通常最好使用其他答案中推荐的
extern
方法


但是,请注意,您通常不应该对
NUM\u socialdem\u文件执行此操作
声明!!!它很好,因为它是在头文件中定义的。除非您试图做一些不寻常的事情,否则标量常量通常应该在头文件中用初始值设定项定义——这样,它们可以在所有翻译单元中被视为编译时常量,这是一件非常有价值的事情。因此,请注意一些其他答案中提出的奇怪建议,即将
NUM\u socialdem\u文件的定义也移动到
.cpp
文件中-这实际上毫无意义,而且是完全错误的做法。

你所说的int和double参数“在编译的代码中从未显示”是什么意思?我的所有其他参数都是常量数字类型,并且似乎在我的