Поделиться через


Ошибка средств компоновщика LNK2019

неразрешенный внешний символ "символ", на который ссылается функция "function"

Скомпилированный код функции делает ссылку или вызов символа, но компоновщик не может найти определение символа в любом из библиотек или файлов объектов.

За этим сообщением об ошибке следует неустранимая ошибка LNK1120. Чтобы устранить ошибку LNK1120, сначала необходимо исправить все LNK2001 и LNK2019 ошибки.

Возможные причины

Существует множество способов получить эту ошибку. Все из них включают ссылку на функцию или переменную, для которых компоновщик не мог разрешить или найти определение. Компилятор может определить, когда символ не объявлен, но не может определить, когда символ не определен. Это связано с тем, что определение может находиться в другом исходном файле или библиотеке. Если символ ссылается на символ, но никогда не определен, компоновщик создает неразрешенную ошибку внешнего символа.

Ниже приведены некоторые распространенные проблемы, вызывающие ошибку LNK2019.

Исходный файл, содержащий определение символа, не компилируется

В Visual Studio убедитесь, что исходный файл, определяющий символ, компилируется как часть проекта. Проверьте выходной каталог промежуточной сборки для соответствующего файла .obj. Если исходный файл не компилируется, щелкните правой кнопкой мыши файл в Обозреватель решений, а затем выберите свойства, чтобы проверить свойства файла. На странице "Общие свойства>конфигурации" должен отображаться тип элемента компилятора C/C++. В командной строке убедитесь, что исходный файл, содержащий определение, компилируется.

Файл объекта или библиотека, содержащая определение символа, не связана

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

Объявление символа не совпадает с определением символа.

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

Функция используется, но тип или число параметров не совпадают с определением функции.

Объявление функции должно соответствовать определению. Убедитесь, что вызов функции соответствует объявлению и что объявление соответствует определению. Код, вызывающий шаблоны функций, также должен иметь соответствующие объявления шаблона функции, которые включают те же параметры шаблона, что и определение. Пример несоответствия объявления шаблона см. в примере LNK2019e.cpp в разделе "Примеры".

Функция или переменная объявлена, но не определена

LNK2019 может возникать, если объявление существует в файле заголовка, но не реализуется соответствующее определение. Для функций-членов или static элементов данных реализация должна включать селектор области класса. Пример см. в разделе Missing Function Body or Variable.

Соглашение о вызове отличается от объявления функции и определения функции.

Некоторые соглашения о вызовах (__cdecl, , __stdcall__fastcallи__vectorcall) кодируются как часть декорированного имени. Убедитесь, что соглашение о вызове совпадает.

Символ определяется в файле C, но объявлен без использования extern "C" в файле C++

Файл, скомпилированный как C, создает декорированные имена, symbols которые отличаются от украшенных имен для того же symbols объявленного в файле C++, если только вы не используете extern "C" модификатор. Убедитесь, что объявление соответствует компоновке компиляции для каждого символа. Аналогично, если символ определяется в файле C++, который будет использоваться программой C, в определении следует использовать extern "C" .

Символ определяется как static и позже ссылается за пределами файла.

В C++, в отличие от C, глобальные константы имеют компоновку static . Чтобы обойти это ограничение, можно включить инициализации const в заголовок файла и ввести этот заголовок в CPP-файлы или можно присвоить переменной неконстантное значение и использовать для доступа к ней константную ссылку.

Элемент static класса не определен

Член static класса должен иметь уникальное определение или будет нарушать правило одноопределенного определения. Член static класса, который не может быть определен встроенным, должен быть определен в одном исходном файле с помощью полного имени. Если он не определен вообще, компоновщик создает LNK2019.

Зависимость сборки определяется только как зависимость проекта в решении

В более ранних версиях Visual Studio этот уровень зависимостей был достаточно. Однако начиная с Visual Studio 2010 Visual Studio требует ссылки на проект в проект. Если у вашего проекта нет ссылки на проект в проект, может появиться эта ошибка компоновщика. Чтобы устранить ошибку, добавьте ссылку одного проекта на другой.

Точка входа не определена

Код приложения должен определить соответствующую точку входа: main или wmain для консольных приложений, а WinMain также wWinMain для приложений Windows. Дополнительные сведения см. в разделе main "Аргументы функции" и "Командная строка" или WinMain "Функция". Чтобы использовать пользовательскую точку входа, укажите /ENTRY параметр компоновщика (символ точки входа).

Создание консольного приложения с помощью параметров для приложения Windows

Если сообщение об ошибке похоже на неразрешенный внешний символ WinMain , на который ссылается функция function_name, ссылка используется /SUBSYSTEM:CONSOLE вместо /SUBSYSTEM:WINDOWS. Дополнительные сведения об этом параметре и инструкции по настройке этого свойства в Visual Studio см. в разделе /SUBSYSTEM (Указание подсистемы).

Библиотеки и файлы объектов, связанные с кодом, должны быть компилированы для той же архитектуры, что и код. Убедитесь, что библиотеки, на которые ссылается проект, компилируются для той же архитектуры, что и проект. Убедитесь, /LIBPATH что свойство или дополнительное свойство каталогов библиотек указывает на библиотеки , созданные для правильной архитектуры.

Вы используете различные параметры компилятора для подстраивание функций в разных исходных файлах

Использование встроенных функций, определенных в CPP-файлах, и смешение в различных исходных файлах параметров компилятора для встраивания функций может привести к возникновению ошибки LNK2019. Для получения дополнительной информации см. Function Inlining Problems.

Автоматические переменные используются вне области

Автоматические переменные (области видимости функции) могут использоваться только в области видимости данной функции. Эти переменные не могут объявляться extern и использоваться в других исходных файлах. Пример см. в разделе Automatic (Function Scope) Variables.

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

Например, если вы используете встроенную AVX2 функцию, но не указывайте /ARCH:AVX2 параметр компилятора, компилятор предполагает, что встроенная функция является внешней функцией. Вместо создания встроенной инструкции компилятор создает вызов внешнего символа с тем же именем, что и у встроенного. Когда компоновщик пытается найти определение этой отсутствующей функции, он создает ошибку LNK2019. Убедитесь, что используются только встроенные и типы, поддерживаемые целевой архитектурой.

Вы смешиваете код, использующий машинный wchar_t код с кодом, который не используется

Работа по соответствию языка C++ в Visual Studio 2005 сделала wchar_t собственный тип по умолчанию. Если не все файлы были скомпилированы с помощью /Zc:wchar_t одинаковых параметров, ссылки на тип могут не разрешаться для совместимых типов. Убедитесь, что wchar_t типы во всех библиотеках и файлах объектов совместимы. Обновление из wchar_t typedef или использование согласованных /Zc:wchar_t параметров при компиляции.

Библиотека static , созданная с помощью версии Visual Studio до Visual Studio 2015, может вызвать LNK2019 ошибки при связывании с UCRT. Файлы <stdio.h><conio.h>заголовков UCRT и <wchar.h>теперь определяют множество *printf* вариантов *scanf* как inline функции. Встроенные функции реализуются меньшим набором общих функций. Отдельные exports для встроенных функций недоступны в стандартных библиотеках UCRT, которые экспортируют только общие функции. Существует несколько способов устранения этой проблемы. Мы рекомендуем перестроить устаревшую библиотеку с текущей версией Visual Studio. Убедитесь, что код библиотеки использует стандартные заголовки для определений *printf* и *scanf* функций, вызвавших ошибки. Еще одним вариантом для устаревшей библиотеки, которую нельзя перестроить, является добавление legacy_stdio_definitions.lib в список библиотек, которые вы связываете. Этот файл библиотеки предоставляет symbols *printf* функции, *scanf* которые встраиваются в заголовки UCRT. Дополнительные сведения см. в разделе "Библиотеки" в разделе "Общие сведения о потенциальных проблемах обновления".

Проблемы со сторонними библиотеками и vcpkg

Если эта ошибка возникает при попытке настроить стороннюю библиотеку в рамках сборки, рассмотрите возможность использования vcpkg. vcpkg — это диспетчер пакетов C++, использующий существующие средства Visual Studio для установки и сборки библиотеки. vcpkg поддерживает большой и растущий список сторонних библиотек. Он задает все свойства конфигурации и зависимости, необходимые для успешной сборки в рамках проекта.

Средства диагностики

Иногда трудно определить, почему компоновщик не может найти определенное определение символов. Часто проблема заключается в том, что вы не включили код, содержащий определение в сборке. Кроме того, параметры сборки создали различные декорированные имена для внешних symbols. Существует несколько средств и параметров, которые помогут диагностировать ошибки LNK2019.

  • Параметр /VERBOSE компоновщика поможет определить, какие файлы ссылается компоновщик. Этот параметр поможет проверить, включен ли в сборку файл, содержащий определение символа.

  • /SYMBOLS Служебная DUMPBIN /EXPORTS программа поможет вам определить, какие symbols из .dll и файлов библиотеки определены в .dll и файлах объектов или библиотек. Убедитесь, что экспортированные декорированные имена соответствуют декорированным именам компоновщика.

  • Служебная UNDNAME программа может показать эквивалентный неоцененный внешний символ для декорированного имени.

Примеры

Ниже приведены несколько примеров кода, вызывающего ошибки LNK2019, а также сведения об устранении ошибок.

Символ объявлен, но не определен

В этом примере внешняя переменная объявлена, но не определена:

// LNK2019.cpp
// Compile by using: cl /EHsc /W4 LNK2019.cpp
// LNK2019 expected
extern char B[100];   // B isn't available to the linker
int main() {
   B[0] = ' ';   // LNK2019
}

Ниже приведен еще один пример объявления переменной и функции, extern но не указано определение:

// LNK2019c.cpp
// Compile by using: cl /EHsc LNK2019c.cpp
// LNK2019 expected
extern int i;
extern void g();
void f() {
   i++;
   g();
}
int main() {}

Если i и g не определены в одном из файлов, включенных в сборку, компоновщик создает LNK2019. Чтобы исправить ошибки, включите файл исходного кода, который содержит определения, в процесс компиляции. Кроме того, можно передать .obj файлы или .lib файлы, содержащие определения компоновщика.

Элемент static данных объявлен, но не определен

LNK2019 также может возникать, когда static член данных объявлен, но не определен. В следующем примере показано возникновение ошибки LNK2019 и приводятся сведения по ее устранению.

// LNK2019b.cpp
// Compile by using: cl /EHsc LNK2019b.cpp
// LNK2019 expected
struct C {
   static int s;
};

// Uncomment the following line to fix the error.
// int C::s;

int main() {
   C c;
   C::s = 1;
}

Параметры объявления не соответствуют определению

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

// LNK2019e.cpp
// compile by using: cl /EHsc LNK2019e.cpp
// LNK2019 expected
#include <iostream>
using namespace std;

template<class T> class
Test {
   // The operator<< declaration doesn't match the definition below:
   friend ostream& operator<<(ostream&, Test&);
   // To fix, replace the line above with the following:
   // template<typename T> friend ostream& operator<<(ostream&, Test<T>&);
};

template<typename T>
ostream& operator<<(ostream& os, Test<T>& tt) {
   return os;
}

int main() {
   Test<int> t;
   cout << "Test: " << t << endl;   // LNK2019 unresolved external
}

Несогласованные wchar_t определения типов

В этом примере создается библиотека DLL с экспортом, который использует WCHAR, в который разрешается wchar_t.

// LNK2019g.cpp
// compile with: cl /EHsc /LD LNK2019g.cpp
#include "windows.h"
// WCHAR resolves to wchar_t
__declspec(dllexport) void func(WCHAR*) {}

Следующий пример использует библиотеку DLL в предыдущем примере и создает LNK2019, так как типы unsigned short* и WCHAR* не совпадают.

// LNK2019h.cpp
// compile by using: cl /EHsc LNK2019h LNK2019g.lib
// LNK2019 expected
__declspec(dllimport) void func(unsigned short*);

int main() {
   func(0);
}

Чтобы устранить эту ошибку, измените unsigned short wchar_t WCHARили скомпилируйте LNK2019g.cpp с помощью./Zc:wchar_t-

См. также

Дополнительные сведения о возможных причинах и решениях для LNK2019, LNK2001 и LNK1120 ошибок см. в вопросе Stack Overflow: What is an undefined reference/unresolved external symbol error and how do I fix it?