Дубликат символа --- Разница между определением и объявлением - PullRequest
2 голосов
/ 28 сентября 2019

Проблема

Я новичок в C ++, и я делаю домашнюю работу, которая отображает различные дистрибутивы в консоли, но мой проект не будет компилироваться.Когда у меня все было в одном файле, все работало нормально и прекрасно, но мой профессор хочет, чтобы мы разбили вещи на файл hpp, файл cpp и основной файл.Я просто переместил все, и теперь он не будет компилироваться из-за ошибки дублирования символов.

Определение против декларации

Я понимаю, что вы хотите включить только объявления функций в ваш заголовочный файл, поэтому я добавил их, но сохранил фактические определения функций в файле cpp.У меня есть оператор include в файле cpp, который включает в себя файл заголовка, и еще один в main.cpp, который включает файл cpp.
Я понимаю, что моя проблема может иметь какое-то отношение к моим операторам include, но япотеряно на том, как это исправить.

Distribution.hpp

Этот файл является определением класса и объявлениями четырех функций, которые я написал

#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);

Distribution.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);

, так как мои функции определяются в Distribution.cpp.

Я использую Xcode v11.0 на Mac.

Кто-нибудь помогаетпочему я получаю ошибки компиляции?

Ответы [ 2 ]

1 голос
/ 28 сентября 2019

Обратите внимание, что это ошибка компоновщика , а не компилятора.

Представьте исполняемое здание как двухэтапный процесс.

  • Сначалана этапе компилятор читает исходный код и генерирует файлы .o.
  • На втором этапе компоновщик читает файлы .o (и другие) и генерирует исполняемые файлы.

Файлы .o имеют двоичные коды и ссылки на символы.Компилятор генерирует два вида вещей: двоичный код с функциями , определенными , и ссылки на символы с функциями , объявленными, но не определенными .Задача компоновщика состоит в том, чтобы решить все ссылки, то есть связать все ссылки на символы с двоичным кодом, чтобы создать полный исполняемый файл.

В вашем примере, похоже, происходит то, что ваши сценарии сборки выполняют следующее:

  • Скомпилируйте файл 'main.cpp' + 'Distribution.Cpp' (входит в комплект) в файл 'main.o'
  • Скомпилируйте файл 'Distribution.cpp' в 'Distribution.o'
  • Свяжите вместе 'main.o' + 'distribtions.o' в конечный исполняемый файл

Таким образом, компоновщик имеет две копии скомпилированного кода из Distribution.cpp, одну в main.oа другой - в дистрибутивах. o

Чтобы решить эту проблему, вам нужно выполнить одно из следующих действий:

  • Поручить компоновщику использовать только main.o для создания исполняемого файла.

или,

  • Заменить # include "distribtions.cpp" на # include "distribtions.hpp" , чтобыВаш файл main.o будет содержать только ссылки на символы, а компоновщик склеит symbols и код из Distribution.o в исполняемый файл.
0 голосов
/ 28 сентября 2019

Вы должны #include "distributions.hpp" в main.cpp вместо #include "distributions.cpp", но вы также должны включить все заголовки, от которых зависит ваш прототип функции в начале, если "distributions.hpp":

#include <vector>
#include <cstdint>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...