Что такое неопределенная ссылка / неразрешенная внешняя ошибка символа и как ее исправить?

Что такое неопределенные ссылки / неразрешенные ошибки внешних символов? Каковы общие причины и как их исправить / предотвратить?

Не стесняйтесь редактировать / добавлять свои собственные.

41 ответ

Функции или методы класса определены в исходных файлах с inline спецификатор.

Пример:-

main.cpp

#include "gum.h"
#include "foo.h"

int main()
{
    gum();
    foo f;
    f.bar();
    return 0;
}

foo.h (1)

#pragma once

struct foo {
    void bar() const;
};

gum.h (1)

#pragma once

extern void gum();

foo.cpp (1)

#include "foo.h"
#include <iostream>

inline /* <- wrong! */ void foo::bar() const {
    std::cout << __PRETTY_FUNCTION__ << std::endl;
}

gum.cpp (1)

#include "gum.h"
#include <iostream>

inline /* <- wrong! */ void gum()
{
    std::cout << __PRETTY_FUNCTION__ << std::endl;
}

Если вы укажете, что gum (так же, foo::bar) является inline при его определении тогда компилятор будет встроен gum (если он захочет):

  • не испуская какое-либо уникальное определение gum, и поэтому
  • не испускает никакого символа, с помощью которого компоновщик может ссылаться на определение gum, и вместо того, чтобы
  • заменить все звонки на gum со встроенными копиями скомпилированного тела gum,

В результате, если вы определите gum встроенный в исходный файл gum.cpp, он скомпилирован в объектный файл gum.o в котором все призывы к gum встроены, и не определен символ, по которому может ссылаться компоновщик gum, Когда вы ссылаетесь gum.o в программу вместе с другим объектным файлом, например main.oкоторые делают ссылки на внешний символ gumкомпоновщик не может разрешить эти ссылки. Таким образом, связь не работает:

Обобщение:

g++ -c  main.cpp foo.cpp gum.cpp

Ссылка на сайт:

$ g++ -o prog main.o foo.o gum.o
main.o: In function `main':
main.cpp:(.text+0x18): undefined reference to `gum()'
main.cpp:(.text+0x24): undefined reference to `foo::bar() const'
collect2: error: ld returned 1 exit status

Вы можете только определить gum как inline если компилятор может увидеть свое определение в каждом исходном файле, в котором gum можно назвать. Это означает, что его встроенное определение должно существовать в заголовочном файле, который вы включаете в каждый исходный файл, в который вы компилируете gum можно назвать. Сделайте одно из двух:

Либо не включайте определения

Удалить inline спецификатор из определения исходного файла:

foo.cpp (2)

#include "foo.h"
#include <iostream>

void foo::bar() const {
    std::cout << __PRETTY_FUNCTION__ << std::endl;
}

gum.cpp (2)

#include "gum.h"
#include <iostream>

void gum()
{
    std::cout << __PRETTY_FUNCTION__ << std::endl;
}

Перестройте с этим:

$ g++ -c  main.cpp foo.cpp gum.cpp
imk@imk-Inspiron-7559:~/develop/so/scrap1$ g++ -o prog main.o foo.o gum.o
imk@imk-Inspiron-7559:~/develop/so/scrap1$ ./prog
void gum()
void foo::bar() const

Успех.

Или правильно

Встроенные определения в заголовочных файлах:

foo.h (2)

#pragma once
#include <iostream>

struct foo {
    void bar() const  { // In-class definition is implicitly inline
        std::cout << __PRETTY_FUNCTION__ << std::endl;
    }
};
// Alternatively...
#if 0
struct foo {
    void bar() const;
};
inline void foo::bar() const  {
    std::cout << __PRETTY_FUNCTION__ << std::endl;
}
#endif

резинка (2)

#pragma once
#include <iostream>

inline void gum() {
    std::cout << __PRETTY_FUNCTION__ << std::endl;
}

Теперь нам не нужно foo.cpp или же gum.cpp:

$ g++ -c main.cpp
$ g++ -o prog main.o
$ ./prog
void gum()
void foo::bar() const

Некоторые опечатки, которые следует учитывать: (часто случалось со мной как новичком)

  • Если вы используете класс: проверьте, не забыли ли вы "classname::" перед именем функции внутри вашего cpp файла, в котором вы определяете функцию.
  • Если вы используете предварительное объявление: обязательно укажите правильный тип. Например: если вы хотите переадресовать объявление «структуры», используйте «структуру», а не «класс».

Использование Visual Studio Code с расширением Code Runner и несколькими файлами .c или .cpp

Поставляемый Code Runner работает только с скомпилированными программами, имеющими один исходный файл. Он не предназначен для использования с несколькими исходными файлами. Вам следует использовать другое расширение, например расширение C/C++ Makefile Project или расширение CMake Tools , или, возможно, исправить расширение Code Runner для работы с несколькими файлами или просто отредактировать файлы конфигурации .json вручную.

Разные архитектуры

Вы можете увидеть сообщение как:

library machine type 'x64' conflicts with target machine type 'X86'

В этом случае это означает, что доступные символы для другой архитектуры, чем та, для которой вы компилируете.

В Visual Studio это происходит из-за неправильной "Платформы", и вам нужно либо выбрать подходящую, либо установить правильную версию библиотеки.

В Linux это может быть связано с неправильной папкой библиотеки (используя lib вместо lib64 например).

В MacOS есть возможность отправить обе архитектуры в одном файле. Может быть так, что ссылка ожидает, что обе версии будут там, но только одна есть. Это также может быть проблема с неправильным lib/lib64 папка, в которой находится библиотека.

Когда вы используете неправильный компилятор для сборки своей программы

Если вы используете или комплекты компилятора, вы должны использовать правильный драйвер компилятора в соответствии с языком, который вы используете. Скомпилируйте и скомпилируйте программу C ++, используя g++ или же clang++. С использованием gcc или же clangвместо этого ссылки на символы стандартной библиотеки C ++ будут неопределенными. Пример:

      $ gcc -o test test.cpp    
/usr/lib/gcc/x86_64-pc-linux-gnu/10.2.0/../../../../x86_64-pc-linux-gnu/bin/ld: /tmp/ccPv7MvI.o: warning: relocation against `_ZSt4cout' in read-only section `.text' 
/usr/lib/gcc/x86_64-pc-linux-gnu/10.2.0/../../../../x86_64-pc-linux-gnu/bin/ld: /tmp/ccPv7MvI.o: in function `main': test.cpp:(.text+0xe): undefined reference to `std::cout' 
/usr/lib/gcc/x86_64-pc-linux-gnu/10.2.0/../../../../x86_64-pc-linux-gnu/bin/ld: test.cpp:(.text+0x13): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)' 
/usr/lib/gcc/x86_64-pc-linux-gnu/10.2.0/../../../../x86_64-pc-linux-gnu/bin/ld: /tmp/ccPv7MvI.o: in function `__static_initialization_and_destruction_0(int, int)': 
test.cpp:(.text+0x43): undefined reference to `std::ios_base::Init::Init()' 
/usr/lib/gcc/x86_64-pc-linux-gnu/10.2.0/../../../../x86_64-pc-linux-gnu/bin/ld: test.cpp:(.text+0x58): undefined reference to `std::ios_base::Init::~Init()' 
/usr/lib/gcc/x86_64-pc-linux-gnu/10.2.0/../../../../x86_64-pc-linux-gnu/bin/ld: warning: creating DT_TEXTREL in a PIE 
collect2: error: ld returned 1 exit status

Мой пример:

заголовочный файл

const string GMCHARACTER("символ"); класс GameCharacter: общедоступный GamePart {частный: строковое имя; статический векторный список символов; public: GameCharacter(cstring nm, cstring id): GamePart(GMCHARACTER, id, TRUE, TRUE, TRUE), name(nm) {}...}

.cpp файл:

vector characterList;...

Это привело к ошибке загрузчика "undefined", поскольку "characterList" был объявлен как статическая переменная-член, но определен как глобальная переменная.

Я добавил это, потому что - хотя кто-то еще перечислил этот случай в длинном списке вещей, на которые следует обратить внимание - в этом списке не было примеров. Это пример того, что нужно искать, особенно в C++.

In my case, I had that error when a class calls a second class within the same DLL. the CPP file of the second class had the wrong Properties->Item Type inside visual studio, in my case it was set to C/C++ Header instead of the correct one C/C++ compiler so the compiler didn't compile the CPP file while building it and cause the Error LNK2019

Ошибка возникает, когда компоновщик не может найти какое-либо определение для определения в файле декларации, то есть из файла заголовка или файла декларации. Это происходит, когда реализация не найдена.

После компиляции компоновщик пытается найти реализации из библиотеки или a для виртуальной функции или для определения шаблона. Если это не находит тогда, эти ошибки происходят согласно архитектуре компоновщика.

  • Код можно скомпилировать как есть, с помощью g ++ 44 (Red Hat 4.4.7-8)

Ubuntu имеет исправленный Debian gcc-4.4 / g ++ - 4.4: плохо с этим кодом (и некоторыми другими кодами / исправлениями ns2).

Ubuntu: mpolsr_umolsr-v1_ns235.patchhttps://drive.google.com/file/d/0B7S...ew?usp=sharing (создан в 2017 году с кодом mpolsr, без изменений.)

tar xvf ns-allinone-2.35_gcc5.tar.gz

https://drive.google.com/file/d/0B7S...ew?usp=sharing

cd ns-allinone-2.35/
patch -p0 < mpolsr_umolsr-v1_ns235.patch  // umolsr version v1.0 is used
./install
              // Stops with MPOLSR.cc
cd ns-2.35/
              // Edit the Makefile line 37 to CPP = g++34 , and run make
make
              // When 'make' stops with an mdart/* error, change to CPP = g++-4.4
make

gcc34 Ubuntu https://drive.google.com/file/d/0B7S255p3kFXNRTkzQnRSNXZ6UVU/view?usp=sharing

g ++ 34 Ubuntu https://drive.google.com/file/d/0B7S255p3kFXNV3J3bnVoWGNWdG8/view?usp=sharing

Эта проблема возникла у меня при объявлении прототипа функции в заголовочном файле:

int createBackground(VertexArray rVA, IntRect arena);

Но затем определение функции в другом месте с использованием ссылки с первым параметром:

int createBackground(VertexArray& rVA, IntRect arena) {}

Тот факт, что прототип не использовал ссылку в первом параметре, в то время как определение использовалось, вызывал эту проблему. Когда я изменил оба, чтобы они соответствовали либо содержащим ссылку, либо не содержащим ссылки, проблема была исправлена.

Ура.

Я создаю общую/динамическую библиотеку. Он работает в Linux и *BSD, но в Mac OS X точно такие же команды компиляции и компоновки вызывают неразрешенные ошибки ссылок. Что дает?

Mac OS X внутренне сильно отличается от Linux и *BSD. Формат объекта/исполняемого файла

В Linux и *BSD при построении разделяемых библиотек неразрешенные ссылки разрешены по умолчанию . Ожидается, что они будут удовлетворены во время загрузки для (пока неизвестного) основного исполняемого файла и/или других разделяемых библиотек. Если эти символы не могут быть разрешены во время загрузки, разделяемая библиотека не загрузится .

В Mac OS X при построении динамических библиотек неразрешенные ссылки по умолчанию запрещены . Если вы ожидаете, что ссылка должна быть разрешена во время загрузки, вам необходимо явно включить неразрешенные ссылки. Это делается с-undefined dynamic_lookupфлаг компоновщика.

Разрешение неразрешенных ссылок полезно при создании загружаемых плагинов .

Другие вопросы по тегам