Страницы

Поиск по вопросам

вторник, 2 октября 2018 г.

Ссылка на неразрешенный внешний символ (возможные причины)

При попытке сборки программы появляется сообщение об ошибке одного из следующих видов:
ссылка на неразрешенный внешний символ ... unresolved external symbol ... undefined reference to ...
Что это значит, и как исправить такую ошибку?


Ответ

Определение:
Данная ошибка означает, что в процессе компоновки программы, компоновщик не смог найти определение некоторой сущности, на которую есть ссылка (попытка использования) в программе.
К таким сущностям может относиться, например, функция или переменная.
Причины и решения:
Возможных причин появления ошибки может быть несколько и это зависит от того, что представляет из себя собираемый проект. Всё множество ситуаций можно разбить на две большие группы:

Используются сторонние библиотеки
Не указана необходимая (статическая) библиотека для компоновщика.
Например, к проекту подключен только *.h файл с объявлениями, но отсутствует код реализации, обычно это *.lib или *.a файлы (в зависимости от используемой системы). Требуется явно подключить библиотеку к проекту. Для Visual C++ это можно сделать добавлением следующей строки прямо в код:
#pragma comment(lib, "libname.lib")
Для gcc/clang требуется указать файл через ключ -l (эль)
Для Qt в .pro файле нужно использовать переменную LIBS
LIBS += -L[путь_к_библиотеке] -l[имя_библиотеки]
Для системы сборки cmake есть target_link_libraries Библиотека указана, но не совпадает разрядность библиотеки и компилируемого кода.
В общем случае, разрядность собираемого проекта (приложения или библиотеки) должна совпадать с разрядностью используемой сторонней библиотеки. Обычно производители библиотек предоставляют возможность выбора 32 или 64 бит версию использовать. Если библиотека поставляется в исходных кодах и собирается отдельно от текущего проекта, нужно также выбрать правильную разрядность. Библиотека указана, но она собрана для другой (не совместимой) ОС.
Например при сборке проекта в Windows осуществляется попытка использовать бинарный файл, собранный для Linux. В данном случае нужно использовать файлы, подходящие для вашей ОС. Библиотека указана, но она собрана другим компилятором, не совместимым с используемым.
Объектные файлы, полученные путем сборки C++ кода разными компиляторами для одной и той же ОС могут быть бинарно несовместимы друг с другом. Требуется использовать совместимые (скорее всего и вовсе одинаковые) компиляторы. Библиотека указана, и собрана тем же компилятором, что и основной проект, но используются разные версии Run-Time библиотек.
Например, для Visual C++ возможна ситуация, когда библиотека собрана с ключом /MDd, а основной проект с /MTd. Требуется задать ключи так, чтобы использовались одинаковые версии Run-Time библиотек.

Сторонние библиотеки не используются
Просто отсутствует определение функции.
void f(int); // всего лишь объявление. Нет `тела` функции int main(){ f(42); // undefined reference to `f(int)' }
Требуется добавить определение функции f
void f(int) { // тело функции } Отсутствует определение статической переменной класса.
struct S { static int i; };
int main() { S s; s.i = 42; // undefined reference to `S::i' }
Нужно добавить определение (выделить память) переменной:
int S::i; Неправильная реализация шаблонного кода.
Например, реализация шаблонного кода помещена в *.cpp файл, хотя она должна находиться полностью в подключаемом *.h файле. Файл с кодом не был скомпилирован.
Например, в случае использования make-файла не было прописано правило построения файла, а в случае использования IDE типа Visual Studio *.cpp файл не добавлен в список файлов проекта. Виртуальная функция в базовом классе не объявлена как =0 (pure-virtual).
struct B { void virtual f(); };
struct D : B { void f() {} };
int main() { D d; }
При использовании иерархии классов функция в базовом классе, не имеющая реализации должна быть помечена как "чистая":
struct B { void virtual f() = 0; }; Имя не имеет внешнего связывания.
Например, есть объявление функции f в модуле А и даже ее реализация в модуле B, но реализация помечена как static
// A.cpp void f(); int main() { f(); // undefined reference to `f()' }
// B.cpp static void f() {}
Аналогичная ситуация может возникнуть при использовании безымянного пространства имен:
// B.cpp namespace { void f() {} }

Комментариев нет:

Отправить комментарий