Duplicate symbol --- 定义和声明的区别
Duplicate symbol --- Difference between definition and declaration
问题
我是 C++ 的新手,我正在做一个在控制台中绘制各种分布的家庭作业问题,但我的项目无法编译。当我将所有内容都放在同一个文件中时,一切都运行良好且花花公子,但我的教授希望我们将其拆分为一个 hpp 文件、一个 cpp 文件和一个主文件。我只是将所有内容都移了过来,现在由于重复符号错误而无法编译。
定义与声明
我知道您只想在头文件中包含函数声明,因此我添加了这些声明,但在 cpp 文件中保留了函数的实际定义。我在包含头文件的 cpp 文件中有一个 include 语句,在 main.cpp 中有另一个包含 cpp 文件的语句。
我知道我的问题可能与我的 include 语句有关,但我不知道如何解决它。
distributions.hpp
这个文件是class我写的四个函数的定义和声明
#include <iostream>
class DistributionPair
{
public:
DistributionPair(std::uint32_t minValue, std::uint32_t maxValue) :
minValue(minValue),
maxValue(maxValue),
count(0)
{
}
std::uint32_t minValue;
std::uint32_t maxValue;
std::uint32_t count;
};
std::vector<DistributionPair> generateUniformDistribution(std::uint32_t, std::uint32_t, std::uint32_t, std::uint8_t);
std::vector<DistributionPair> generateNormalDistribution(std::uint32_t, float, float, std::uint8_t);
std::vector<DistributionPair> generatePoissonDistribution(std::uint32_t, std::uint8_t, std::uint8_t);
void plotDistribution(std::string, const std::vector<DistributionPair>&, const std::uint8_t);
distributions.cpp
此文件包含这四个函数的其余定义
#include <iostream>
#include <iomanip>
#include <random>
#include "distributions.hpp"
std::vector<DistributionPair> generateUniformDistribution(std::uint32_t howMany, std::uint32_t min, std::uint32_t max, std::uint8_t numBins)
{......
main.cpp
这是绘制分布的主要函数
#include <iostream>
#include "distributions.cpp"
int main()
{......
错误信息
以下是我在编译代码时收到的错误消息:
duplicate symbol 'generateUniformDistribution(unsigned int, unsigned int, unsigned int, unsigned char)' in:
/Users/ryanegbert/Desktop/c++/assign2/build/RandDistributions.build/Debug/RandDistributions.build/Objects-normal/x86_64/distributions.o
/Users/ryanegbert/Desktop/c++/assign2/build/RandDistributions.build/Debug/RandDistributions.build/Objects-normal/x86_64/main.o
..........
ld: 4 duplicate symbols for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
如果我使用 #include "distributions.hpp"
那么我会得到一个不同的编译错误:
/Users/ryanegbert/Desktop/c++/assign2/main.cpp:6:20: error: implicit instantiation of undefined template 'std::__1::vector<DistributionPair, std::__1::allocator<DistributionPair> >'
auto uniform = generateUniformDistribution(100000, 0, 79, 40);
因为我的函数是在 distributions.cpp 中定义的。
我在 Mac 上使用 Xcode v11.0。
有人能帮我解释为什么我会遇到这个编译错误吗?
请注意这是一个链接器错误,而不是编译器错误。
将可执行文件构建视为一个两阶段过程。
- 在第一阶段,编译器读取源代码并生成 .o 文件。
- 在第二阶段,链接器读取.o(和其他)文件并生成可执行文件。
.o 文件同时包含二进制代码和符号引用。编译器生成两种东西:函数 已定义 的二进制代码,以及函数 已声明但未定义 的符号引用。链接器的任务是解决所有引用,即将所有符号引用与二进制代码相关联,构建一个完整的可执行文件。
您的示例中似乎发生的是您的构建脚本正在执行以下操作:
- 编译'main.cpp'+'distributions.cpp'(包含)成'main.o'
- 将'distributions.cpp'编译成'distributions.o'
- Link一起'main.o'+'distributions.o'进入最终的可执行文件
这样,链接器就有两份来自 distributions.cpp 的编译代码副本,一份在 main.o 中,另一份在 distributions.o
中
要解决它,您必须执行以下操作之一:
- 指示链接器只使用'main.o'创建可执行文件
或者,
- 将 #include "distributions.cpp" 替换为 #include "distributions.hpp" 以便您的 main.o 文件将只包含符号引用,链接器会将 distributions.o 中的符号和代码粘合到可执行文件中。
您必须在 main.cpp 中 #include "distributions.hpp"
而不是 #include "distributions.cpp"
,但您还必须在开始时包括函数原型所依赖的所有 headers if "distributions.hpp"
:
#include <vector>
#include <cstdint>
问题
我是 C++ 的新手,我正在做一个在控制台中绘制各种分布的家庭作业问题,但我的项目无法编译。当我将所有内容都放在同一个文件中时,一切都运行良好且花花公子,但我的教授希望我们将其拆分为一个 hpp 文件、一个 cpp 文件和一个主文件。我只是将所有内容都移了过来,现在由于重复符号错误而无法编译。
定义与声明
我知道您只想在头文件中包含函数声明,因此我添加了这些声明,但在 cpp 文件中保留了函数的实际定义。我在包含头文件的 cpp 文件中有一个 include 语句,在 main.cpp 中有另一个包含 cpp 文件的语句。
我知道我的问题可能与我的 include 语句有关,但我不知道如何解决它。
distributions.hpp
这个文件是class我写的四个函数的定义和声明
#include <iostream>
class DistributionPair
{
public:
DistributionPair(std::uint32_t minValue, std::uint32_t maxValue) :
minValue(minValue),
maxValue(maxValue),
count(0)
{
}
std::uint32_t minValue;
std::uint32_t maxValue;
std::uint32_t count;
};
std::vector<DistributionPair> generateUniformDistribution(std::uint32_t, std::uint32_t, std::uint32_t, std::uint8_t);
std::vector<DistributionPair> generateNormalDistribution(std::uint32_t, float, float, std::uint8_t);
std::vector<DistributionPair> generatePoissonDistribution(std::uint32_t, std::uint8_t, std::uint8_t);
void plotDistribution(std::string, const std::vector<DistributionPair>&, const std::uint8_t);
distributions.cpp
此文件包含这四个函数的其余定义
#include <iostream>
#include <iomanip>
#include <random>
#include "distributions.hpp"
std::vector<DistributionPair> generateUniformDistribution(std::uint32_t howMany, std::uint32_t min, std::uint32_t max, std::uint8_t numBins)
{......
main.cpp
这是绘制分布的主要函数
#include <iostream>
#include "distributions.cpp"
int main()
{......
错误信息
以下是我在编译代码时收到的错误消息:
duplicate symbol 'generateUniformDistribution(unsigned int, unsigned int, unsigned int, unsigned char)' in:
/Users/ryanegbert/Desktop/c++/assign2/build/RandDistributions.build/Debug/RandDistributions.build/Objects-normal/x86_64/distributions.o
/Users/ryanegbert/Desktop/c++/assign2/build/RandDistributions.build/Debug/RandDistributions.build/Objects-normal/x86_64/main.o
..........
ld: 4 duplicate symbols for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
如果我使用 #include "distributions.hpp"
那么我会得到一个不同的编译错误:
/Users/ryanegbert/Desktop/c++/assign2/main.cpp:6:20: error: implicit instantiation of undefined template 'std::__1::vector<DistributionPair, std::__1::allocator<DistributionPair> >'
auto uniform = generateUniformDistribution(100000, 0, 79, 40);
因为我的函数是在 distributions.cpp 中定义的。
我在 Mac 上使用 Xcode v11.0。
有人能帮我解释为什么我会遇到这个编译错误吗?
请注意这是一个链接器错误,而不是编译器错误。
将可执行文件构建视为一个两阶段过程。
- 在第一阶段,编译器读取源代码并生成 .o 文件。
- 在第二阶段,链接器读取.o(和其他)文件并生成可执行文件。
.o 文件同时包含二进制代码和符号引用。编译器生成两种东西:函数 已定义 的二进制代码,以及函数 已声明但未定义 的符号引用。链接器的任务是解决所有引用,即将所有符号引用与二进制代码相关联,构建一个完整的可执行文件。
您的示例中似乎发生的是您的构建脚本正在执行以下操作:
- 编译'main.cpp'+'distributions.cpp'(包含)成'main.o'
- 将'distributions.cpp'编译成'distributions.o'
- Link一起'main.o'+'distributions.o'进入最终的可执行文件
这样,链接器就有两份来自 distributions.cpp 的编译代码副本,一份在 main.o 中,另一份在 distributions.o
中要解决它,您必须执行以下操作之一:
- 指示链接器只使用'main.o'创建可执行文件
或者,
- 将 #include "distributions.cpp" 替换为 #include "distributions.hpp" 以便您的 main.o 文件将只包含符号引用,链接器会将 distributions.o 中的符号和代码粘合到可执行文件中。
您必须在 main.cpp 中 #include "distributions.hpp"
而不是 #include "distributions.cpp"
,但您还必须在开始时包括函数原型所依赖的所有 headers if "distributions.hpp"
:
#include <vector>
#include <cstdint>