Błąd narzędzi konsolidatora LNK2019
nierozwiązany symbol zewnętrzny "symbol" przywoływany w funkcji "function"
Skompilowany kod funkcji tworzy odwołanie lub wywołanie symbolu, ale konsolidator nie może odnaleźć definicji symboli w żadnym z bibliotek lub plików obiektów.
Po tym komunikacie o błędzie następuje błąd krytyczny LNK1120. Aby naprawić LNK1120 błędów, najpierw należy naprawić wszystkie błędy LNK2001 i LNK2019.
Możliwe przyczyny
Istnieje wiele sposobów, aby uzyskać ten błąd. Wszystkie z nich obejmują odwołanie do funkcji lub zmiennej, której konsolidator nie mógł rozpoznać lub znaleźć definicji. Kompilator może określić, kiedy symbol nie jest zadeklarowany, ale nie może określić, kiedy symbol nie jest zdefiniowany. Jest to spowodowane tym, że definicja może znajdować się w innym pliku źródłowym lub w innej bibliotece. Jeśli symbol jest odwoływany, ale nigdy nie został zdefiniowany, konsolidator generuje nierozwiązany błąd symbolu zewnętrznego.
Poniżej przedstawiono niektóre typowe problemy, które powodują LNK2019:
Plik źródłowy zawierający definicję symbolu nie jest kompilowany
W programie Visual Studio upewnij się, że plik źródłowy definiujący symbol jest kompilowany w ramach projektu. Sprawdź katalog wyjściowy kompilacji pośredniej, aby uzyskać pasujący plik .obj. Jeśli plik źródłowy nie jest skompilowany, kliknij prawym przyciskiem myszy plik w Eksplorator rozwiązań, a następnie wybierz polecenie Właściwości, aby sprawdzić właściwości pliku. Strona Właściwości>konfiguracji Ogólne powinna zawierać typ elementu kompilatora C/C++. W wierszu polecenia upewnij się, że plik źródłowy zawierający definicję jest kompilowany.
Plik obiektu lub biblioteka zawierająca definicję symbolu nie jest połączona
W programie Visual Studio upewnij się, że plik obiektu lub biblioteka zawierająca definicję symboli jest połączona w ramach projektu. W wierszu polecenia upewnij się, że lista plików do połączenia zawiera plik obiektu lub bibliotekę.
Deklaracja symbolu nie jest taka sama jak definicja symbolu
Sprawdź, czy używasz poprawnej pisowni i wielkich liter zarówno w deklaracji, jak i definicji, oraz wszędzie tam, gdzie symbol jest używany lub wywoływany.
Funkcja jest używana, ale typ lub liczba parametrów nie są zgodne z definicją funkcji
Deklaracja funkcji musi być zgodna z definicją. Upewnij się, że wywołanie funkcji jest zgodne z deklaracją i że deklaracja jest zgodna z definicją. Kod, który wywołuje szablony funkcji, musi również mieć zgodne deklaracje szablonu funkcji, które zawierają te same parametry szablonu co definicja. Aby zapoznać się z przykładem niezgodności deklaracji szablonu, zobacz przykładowe LNK2019e.cpp w sekcji Przykłady.
Zadeklarowana jest funkcja lub zmienna, ale nie jest zdefiniowana
LNK2019 może wystąpić, gdy deklaracja istnieje w pliku nagłówka, ale nie zaimplementowano pasującej definicji. W przypadku funkcji składowych lub static składowych danych implementacja musi zawierać selektor zakresu klas. Aby zapoznać się z przykładem, zobacz Brak treści funkcji lub Zmiennej.
Konwencja wywoływania różni się między deklaracją funkcji a definicją funkcji
Niektóre konwencje wywoływania (__cdecl
, __stdcall
, __fastcall
i __vectorcall
) są kodowane jako część nazwy ozdobionej. Upewnij się, że konwencja wywoływania jest taka sama.
Symbol jest zdefiniowany w pliku C, ale zadeklarowany bez użycia extern "C"
w pliku C++
Plik skompilowany jako C tworzy nazwy ozdobione, symbols które różnią się od nazw ozdobionych dla tego samego symbols zadeklarowanego w pliku C++, chyba że używasz extern "C"
modyfikatora. Upewnij się, że deklaracja jest zgodna z połączeniem kompilacji dla każdego symbolu. Podobnie, jeśli zdefiniujesz symbol w pliku C++, który będzie używany przez program języka C, użyj extern "C"
go w definicji.
Symbol jest definiowany jako static , a następnie później przywołyny poza plikiem
W języku C++, w przeciwieństwie do języka C, stałe globalne mają static
powiązania. Aby obejść to ograniczenie, możesz uwzględnić const
inicjalizacji w pliku nagłówka i dołączyć ten nagłówek w plikach .cpp albo ustawić zmienną niestałą i użyć stałego odwołania, aby uzyskać do niego dostęp.
Składowa static klasy nie jest zdefiniowana
Składowa static klasy musi mieć unikatową definicję lub naruszy regułę jednej definicji. Składowa static klasy, której nie można zdefiniować w tekście, musi być zdefiniowana w jednym pliku źródłowym przy użyciu w pełni kwalifikowanej nazwy. Jeśli w ogóle go nie zdefiniowano, konsolidator generuje LNK2019.
Zależność kompilacji jest definiowana tylko jako zależność projektu w rozwiązaniu
We wcześniejszych wersjach programu Visual Studio ten poziom zależności był wystarczający. Jednak począwszy od programu Visual Studio 2010 program Visual Studio wymaga odwołania do projektu. Jeśli projekt nie zawiera odwołania do projektu, może zostać wyświetlony ten błąd konsolidatora. Dodaj odwołanie do projektu, aby rozwiązać ten problem.
Punkt wejścia nie jest zdefiniowany
Kod aplikacji musi definiować odpowiedni punkt wejścia: main
lub wmain
dla aplikacji konsolowych oraz WinMain
wWinMain
dla aplikacji systemu Windows. Aby uzyskać więcej informacji, zobacz funkcja i argumenty wiersza polecenia lub WinMain
funkcja.main
Aby użyć niestandardowego punktu wejścia, określ opcję konsolidatora /ENTRY
(symbol punktu wejścia).
Aplikację konsolową można utworzyć przy użyciu ustawień aplikacji systemu Windows
Jeśli komunikat o błędzie jest podobny do nierozwiązanego symbolu zewnętrznego, do których odwołuje się function_name WinMain funkcji, użyj polecenia /SUBSYSTEM:CONSOLE
zamiast ./SUBSYSTEM:WINDOWS
Aby uzyskać więcej informacji na temat tego ustawienia i instrukcji dotyczących ustawiania tej właściwości w programie Visual Studio, zobacz /SUBSYSTEM
(Określ podsystem).
Próbujesz połączyć biblioteki 64-bitowe z kodem 32-bitowym lub bibliotekami 32-bitowymi do 64-bitowego kodu
Biblioteki i pliki obiektów połączone z kodem muszą być kompilowane dla tej samej architektury co kod. Upewnij się, że biblioteki, do których odwołuje się projekt, są kompilowane dla tej samej architektury co projekt. Upewnij się, że /LIBPATH
właściwość lub Dodatkowe katalogi bibliotek wskazuje biblioteki utworzone dla prawidłowej architektury.
Różne opcje kompilatora służą do tworzenia inliningu funkcji w różnych plikach źródłowych
Użycie wbudowanych funkcji zdefiniowanych w plikach .cpp i mieszanie opcji kompilatora w różnych plikach źródłowych może spowodować LNK2019. Aby uzyskać więcej informacji, zobacz Problemy z podkreśleniami funkcji.
Używasz zmiennych automatycznych poza ich zakresem
Zmienne automatyczne (zakres funkcji) mogą być używane tylko w zakresie tej funkcji. Tych zmiennych nie można zadeklarować extern
i użyć w innych plikach źródłowych. Aby zapoznać się z przykładem, zobacz Zmienne automatycznego (zakresu funkcji).
Wywoływanie funkcji wewnętrznych lub przekazywanie typów argumentów do funkcji wewnętrznych, które nie są obsługiwane w architekturze docelowej
Jeśli na przykład używasz funkcji AVX2 wewnętrznej, ale nie określisz /ARCH:AVX2
opcji kompilatora, kompilator zakłada, że funkcja wewnętrzna jest funkcją zewnętrzną. Zamiast generować instrukcje wbudowane, kompilator generuje wywołanie do symbolu zewnętrznego o takiej samej nazwie jak wewnętrzna. Gdy konsolidator próbuje znaleźć definicję tej brakującej funkcji, generuje LNK2019. Upewnij się, że używasz tylko funkcji wewnętrznych i typów obsługiwanych przez architekturę docelową.
Możesz mieszać kod, który używa natywnego wchar_t
kodu, który nie jest używany
Praca dotycząca zgodności języka C++, która została wykonana w programie Visual Studio 2005, domyślnie wykonała wchar_t
typ natywny. Jeśli nie wszystkie pliki zostały skompilowane przy użyciu tych samych /Zc:wchar_t
ustawień, odwołania do typów mogą nie być rozpoznawane jako zgodne typy. Upewnij się, że wchar_t
typy we wszystkich plikach bibliotek i obiektów są zgodne. Zaktualizuj z wchar_t
definicji typów lub użyj spójnych /Zc:wchar_t ustawień podczas kompilowania.
Występują błędy funkcji *printf*
i *scanf*
podczas łączenia starszej static biblioteki
static Biblioteka, która została utworzona przy użyciu wersji programu Visual Studio przed programem Visual Studio 2015, może powodować błędy LNK2019 podczas nawiązywania linku z narzędziem UCRT. Pliki <stdio.h>
nagłówków UCRT , <conio.h>
i <wchar.h>
teraz definiują wiele *printf*
odmian i *scanf*
jako inline
funkcje. Wbudowane funkcje są implementowane przez mniejszy zestaw typowych funkcji. Pojedyncza exports dla wbudowanych funkcji nie jest dostępna w standardowych bibliotekach UCRT, które eksportują tylko typowe funkcje. Istnieje kilka sposobów rozwiązania tego problemu. Zalecaną metodą jest ponowne skompilowanie starszej biblioteki przy użyciu bieżącej wersji programu Visual Studio. Upewnij się, że kod biblioteki używa standardowych nagłówków definicji *printf*
funkcji i *scanf*
, które spowodowały błędy. Inną opcją dla starszej biblioteki, której nie można ponownie skompilować, jest dodanie legacy_stdio_definitions.lib
do listy linków bibliotek. Ten plik biblioteki zawiera symbols funkcje *printf*
i *scanf*
, które są podkreślone w nagłówkach UCRT. Aby uzyskać więcej informacji, zobacz sekcję Biblioteki w temacie Omówienie potencjalnych problemów z uaktualnieniem.
Problemy z biblioteką innych firm i oprogramowanie vcpkg
Jeśli ten błąd występuje podczas próby skonfigurowania biblioteki innej firmy w ramach kompilacji, rozważ użycie narzędzia vcpkg. vcpkg to menedżer pakietów języka C++, który używa istniejących narzędzi programu Visual Studio do instalowania i kompilowania biblioteki. Narzędzie vcpkg obsługuje dużą i rosnącą listę bibliotek innych firm. Ustawia wszystkie właściwości konfiguracji i zależności wymagane do pomyślnych kompilacji w ramach projektu.
Narzędzia do diagnostyki
Czasami trudno stwierdzić, dlaczego konsolidator nie może odnaleźć określonej definicji symboli. Często problem polega na tym, że nie dołączono kodu zawierającego definicję w kompilacji. Lub opcje kompilacji utworzyły różne nazwy ozdobione dla zewnętrznego symbols. Istnieje kilka narzędzi i opcji, które mogą ułatwić diagnozowanie błędów LNK2019.
Opcja
/VERBOSE
konsolidatora może pomóc w określeniu plików, do których odwołuje się konsolidator. Ta opcja może pomóc w sprawdzeniu, czy plik zawierający definicję symbolu znajduje się w kompilacji.Opcje
/EXPORTS
i/SYMBOLS
narzędzia mogą pomóc w odnalezieniu DUMPBIN zdefiniowanych symbols w plikach .dll i obiektów lub bibliotek. Upewnij się, że wyeksportowane nazwy ozdobione są zgodne z nazwami ozdobionymi wyszukiwanymi przez konsolidatora.Narzędzie UNDNAME może wyświetlić odpowiednik nieukodowanego symbolu zewnętrznego dla nazwy ozdobionej.
Przykłady
Poniżej przedstawiono kilka przykładów kodu, który powoduje błędy LNK2019 wraz z informacjami na temat naprawiania błędów.
Symbol jest zadeklarowany, ale nie jest zdefiniowany
W tym przykładzie zadeklarowana jest zmienna zewnętrzna, ale nie jest zdefiniowana:
// 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
}
Oto inny przykład, w którym zmienna i funkcja są deklarowane jako extern
, ale nie podano definicji:
// LNK2019c.cpp
// Compile by using: cl /EHsc LNK2019c.cpp
// LNK2019 expected
extern int i;
extern void g();
void f() {
i++;
g();
}
int main() {}
Jeśli element i
i nie g
jest zdefiniowany w jednym z plików zawartych w kompilacji, konsolidator generuje LNK2019. Błędy można naprawić, dołączając plik kodu źródłowego, który zawiera definicje w ramach kompilacji. Alternatywnie można przekazać .obj
pliki lub .lib
pliki zawierające definicje do konsolidatora.
Element static członkowski danych jest zadeklarowany, ale nie jest zdefiniowany
LNK2019 może również wystąpić, gdy element static członkowski danych jest zadeklarowany, ale nie jest zdefiniowany. Poniższy przykład generuje LNK2019 i pokazuje, jak go naprawić.
// 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;
}
Parametry deklaracji nie są zgodne z definicją
Kod, który wywołuje szablony funkcji, musi mieć zgodne deklaracje szablonów funkcji. Deklaracje muszą zawierać te same parametry szablonu co definicja. Poniższy przykład generuje LNK2019 na operatorie zdefiniowanym przez użytkownika i pokazuje, jak go naprawić.
// 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
}
Niespójne wchar_t definicje typów
W tym przykładzie jest tworzona biblioteka DLL zawierająca eksport, który używa WCHAR
elementu , który jest rozpoznawany jako wchar_t
.
// LNK2019g.cpp
// compile with: cl /EHsc /LD LNK2019g.cpp
#include "windows.h"
// WCHAR resolves to wchar_t
__declspec(dllexport) void func(WCHAR*) {}
Następny przykład używa biblioteki DLL w poprzednim przykładzie i generuje LNK2019, ponieważ typy unsigned short*
i WCHAR*
nie są takie same.
// LNK2019h.cpp
// compile by using: cl /EHsc LNK2019h LNK2019g.lib
// LNK2019 expected
__declspec(dllimport) void func(unsigned short*);
int main() {
func(0);
}
Aby rozwiązać ten błąd, zmień wartość unsigned short
na wchar_t
lub WCHAR
lub skompiluj LNK2019g.cpp przy użyciu polecenia /Zc:wchar_t-
.
Zobacz też
Aby uzyskać więcej informacji o możliwych przyczynach i rozwiązaniach dotyczących błędów LNK2019, LNK2001 i LNK1120, zobacz pytanie Stack Overflow: What is an undefined reference/unresolved external symbol error and how do I fix it?
.