我喜欢帮助诊断我尝试使用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
Run Code Online (Sandbox Code Playgroud)
只有在我将此声明包含在名为的文件中时才会发生错误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
Run Code Online (Sandbox Code Playgroud)
我搜索了所有文件,这是唯一SOCIODEM_FILENAMES宣布的地方.当我注释掉声明时,"重复符号"错误消失了.
我不熟悉链接器错误(如果这就是这个),并希望帮助解决问题.我的所有头文件都有#ifndef...#define...#endif包装器.我的编译命令是
g++ -o a.out -I /Applications/boost_1_42_0/ Host.cpp Simulation.cpp main.cpp Rdraws.cpp
Run Code Online (Sandbox Code Playgroud)
提前致谢.
解决方案摘要
我现在在Parameters.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" };
Run Code Online (Sandbox Code Playgroud)
Parameters.h中的所有其他定义和声明都保持不变.安德烈和其他评论者总结了一种替代方法extern,这对我来说是过度的.
AnT*_*AnT 14
由于某些原因,到目前为止,没有一个答案可以解释整数NUM_SOCIODEM_FILES对象和数组SOCIODEM_FILENAMES对象之间的区别.后者由于已解释的原因触发链接器错误:因为您将头文件包含到多个实现文件中.然而,前者会毫无问题地联系起来(因为NUM_SOCIODEM_FILES宣言确实没有问题).为什么?
原因是你的NUM_SOCIODEM_FILES对象被声明了const.在C++中,const对象默认具有内部链接,这意味着即使它们在多个实现文件中定义,它们也不会导致链接问题.换句话说,在C++中你NUM_SOCIODEM_FILES的等同于
static const int NUM_SOCIODEM_FILES = 5; /* internal linkage */
Run Code Online (Sandbox Code Playgroud)
这就是为什么它不会导致任何链接问题.
同时你SOCIODEM_FILENAMES的声明不是常量,这就是默认情况下它获得外部链接并最终导致链接器错误的原因.但如果你宣布你的SOCIODEM_FILENAMES同样const,问题就会消失
const char * const SOCIODEM_FILENAMES[ NUM_SOCIODEM_FILES ] = {
...
Run Code Online (Sandbox Code Playgroud)
注意额外const的位置在声明中.如果您只是添加额外的内容const并保留其他所有内容(即SOCIODEM_FILENAMES在头文件中保留定义),即使您将头文件包含在多个翻译单元中,链接器也不会报告错误.
这不是一种推荐的方法,因为这样你就会给你的SOCIODEM_FILENAMES内部链接,并SOCIODEM_FILENAMES在每个翻译单元中最终得到一个独立的数组副本- 这可能工作正常,但仍然没有多大意义.因此,对于您的阵列,通常最好使用extern其他答案中建议的方法.
但请注意,您通常不应该NUM_SOCIODEM_FILES申报!!! 它很好,在头文件中定义.除非你试图做一些不寻常的事情,否则通常应该在头文件中使用初始化程序定义标量常量- 这样它们可以被视为所有翻译单元中的编译时常量,这是一个相当有价值的东西.所以,要注意一些其他答案中存在的奇怪建议,也就是将文件的定义NUM_SOCIODEM_FILES移到.cpp文件中 - 这实际上没有任何意义,这是完全错误的事情.
最有可能的是,您#include将此文件存储在多个源文件中.问题是每个包含都会导致名为变量的单独定义SOCIODEM_FILENAMES.包括警卫没有帮助.包含防护措施可防止单个编译单元中的多个声明 ; 它们不会阻止多个编译单元的多个定义.
您需要做的是extern在标题中声明这些变量,然后在一个源文件中定义它们.例如
// Parameters.h
#ifndef PARAMETERS_H
#define PARAMETERS_H
// ...[code snipped]...
extern const int NUM_SOCIODEM_FILES;
extern const char * SOCIODEM_FILENAMES[];
// ...[code snipped]...
#endif
Run Code Online (Sandbox Code Playgroud)
然后:
// 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" };
Run Code Online (Sandbox Code Playgroud)
你可以逃避不这样做,int因为它是一个常量整数,所以编译器可以把它当作编译时常量,它永远不会出现在编译代码中.但是,char*不能这样处理,因此必须有一个定义(在C++中称为"一个定义规则").
| 归档时间: |
|
| 查看次数: |
4026 次 |
| 最近记录: |