Что такое неопределенная ссылка / неразрешенная внешняя ошибка символа и как ее исправить?
Что такое неопределенные ссылки / неразрешенные ошибки внешних символов? Каковы общие причины и как их исправить / предотвратить?
Не стесняйтесь редактировать / добавлять свои собственные.
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.patch
→ https://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
флаг компоновщика.
Разрешение неразрешенных ссылок полезно при создании загружаемых плагинов .