Condividi tramite


Errore degli strumenti del linker LNK2019

Riferimento al simbolo esterno 'simbolo' non risolto nella funzione 'funzione'

Il linker non è riuscito a trovare una definizione per il simbolo esterno "symbol" usato nella funzione "function". Questo errore può essere causato da molti problemi. Questo argomento consente di identificare la causa e di trovare una soluzione.

Un simbolo esterno è il nome dichiarato usato nel codice sorgente per fare riferimento a un elemento definito in un altro modulo, ad esempio una funzione esterna o una variabile globale. Il linker è responsabile della risoluzione di tutti i riferimenti al simbolo esterno in ogni modulo quando vengono collegati in un'applicazione o DLL. Se il linker non riesce a trovare una definizione corrispondente per un simbolo esterno in uno dei file collegati, viene generato l'errore LNK2019. Questo errore può verificarsi se il file di codice sorgente o di libreria contenente la definizione del simbolo non viene incluso nella compilazione. Può anche verificarsi se il nome cercato dal linker non corrisponde al nome del simbolo nel modulo che lo definisce.

Il codice che usa il collegamento C++ usa la Decorazione dei nomi, nota anche come alterazione dei nomi, per codificare le informazioni aggiuntive su un tipo di simbolo e chiamando la convenzione insieme al nome del simbolo. Il nome decorato è il nome cercato dal linker per risolvere i simboli esterni. Poiché diventa parte del nome decorato del simbolo, se il tipo di dichiarazione del riferimento al simbolo non corrisponde al tipo di dichiarazione della definizione del simbolo, può verificarsi l'errore LNK2019. Il messaggio di errore mostra sia il simbolo esterno che il relativo nome decorato per consentire di trovare la causa dell'errore.

Problemi comuni

Di seguito sono riportati alcuni problemi comuni che causano l'errore LNK2019:

  • La dichiarazione del simbolo non è stata digitata nello stesso modo in cui è stata digitata la definizione del simbolo. Verificare che i valori siano stati digitati correttamente.

  • Viene usata una funzione, ma il tipo o il numero dei parametri non corrisponde alla definizione della funzione. La dichiarazione della funzione deve corrispondere alla definizione. Il codice che richiama le funzioni modello deve contenere anche le dichiarazioni delle funzioni modello corrispondenti che includono gli stessi parametri modello della definizione. Verificare che la chiamata di funzione corrisponda alla dichiarazione e che la dichiarazione corrisponda alla definizione.

  • Una funzione o una variabile viene dichiarata ma non definita. Per un esempio vedere Codice di funzione o variabile mancante.

  • La convenzione di chiamata è diversa tra la dichiarazione di funzione e la definizione di funzione. Le convenzioni di chiamata (__cdecl, __stdcall, __fastcall, or __vectorcall) sono codificate come parte del nome decorato. Verificare che la convenzione di chiamata sia la stessa.

  • Un simbolo viene definito in un file C, ma viene dichiarato senza l'uso di extern "C" in un file C++. I simboli definiti in un file compilato come C hanno nomi decorati diversi rispetto ai simboli dichiarati in un file C++, a meno che non venga usato il modificatore extern "C". Verificare che la dichiarazione corrisponda al collegamento di compilazione per ogni simbolo.

    Analogamente, se si definisce un simbolo in un file di C++ che verrà usato da un programma C, usare extern "C" nella definizione.

  • Un simbolo viene definito come static e successivamente vi viene fatto riferimento all'esterno del file. In C++, diversamente da C, le costanti globali contengono un collegamento static. Per evitare questa limitazione, è possibile includere le inizializzazioni const in un file di intestazione e includere l'intestazione nei file cpp o è possibile rendere la variabile non costante e usare un riferimento costante per accedervi.

  • Un membro statico di una classe non è definito. Un membro statico di una classe deve avere una definizione univoca, altrimenti violerà la regola della definizione unica. Un membro statico di una classe che non può essere definito inline deve essere definito in un unico modulo usando il nome completo. Se non viene definito in alcun modo, il linker genera l'errore LNK2019.

  • Una dipendenza di compilazione viene definita solo come dipendenza di progetto nella soluzione. Nelle versioni precedenti di Visual Studio questo livello di dipendenza è sufficiente. Tuttavia, a partire da Visual Studio 2010, Visual Studio richiede un riferimento da progetto a progetto. Se il progetto non contiene un riferimento da progetto a progetto, è possibile che venga visualizzato questo errore del linker. Aggiungere un riferimento da progetto a progetto per risolvere il problema.

  • Un'applicazione console viene compilata usando le impostazioni di un'applicazione Windows. Se il messaggio di errore è unresolved external symbol _WinMain@16 referenced in function ___tmainCRTStartup, eseguire il collegamento usando /SUBSYSTEM:CONSOLE anziché /SUBSYSTEM:WINDOWS. Per altre informazioni su questa impostazione e per istruzioni su come impostare questa proprietà in Visual Studio, vedere /SUBSYSTEM (Specifica il sottosistema).

  • Vengono usate opzioni del compilatore diverse per l'inline delle funzioni in moduli diversi. L'uso delle funzioni inline definite nei file cpp e la combinazione di opzioni del compilatore per l'inline delle funzioni in moduli diversi può causare l'errore LNK2019. Per altre informazioni, vedere Problemi di inline di funzioni.

  • Vengono usate variabili automatiche al di fuori dell'ambito. Le variabili automatiche (ambito funzione) possono essere usate solo nell'ambito di tale funzione. Queste variabili non possono essere dichiarate extern e usate in altri moduli. Per un esempio vedere Variabili automatiche (ambito funzione).

  • Vengono chiamate funzioni intrinseche o vengono passati tipi di argomento alle funzioni intrinseche non supportati nell'architettura di destinazione. Se ad esempio si usa un elemento AVX2 intrinseco, ma non si specifica l'opzione del compilatore /ARCH:AVX2, il compilatore presuppone che l'elemento intrinseco sia una funzione esterna. Anziché generare un'istruzione inline, il compilatore genera una chiamata a un simbolo esterno con lo stesso nome dell'elemento intrinseco. Quando il linker prova a cercare la definizione di questa funzione mancante, viene generato l'errore LNK2019. Verificare di usare solo elementi intrinseci e tipi supportati dall'architettura di destinazione.

  • Viene combinato codice che usa wchar_t nativo con codice che non lo usa. Le operazioni di conformità del linguaggio C++ eseguite in Visual C++ 2005 hanno reso wchar_t un tipo nativo per impostazione predefinita. È necessario usare l'opzione del compilatore /Zc:wchar_t- per generare codice compatibile con i moduli compilati con le versioni precedenti di Visual C++. Se non tutti i moduli sono stati compilati usando le stesse impostazioni di /Zc:wchar_t, i riferimenti ai tipi non possono essere risolti in tipi compatibili. Verificare che i tipi wchar_t in tutti i moduli siano compatibili aggiornando i tipi usati o usando impostazioni di /Zc:wchar_t coerenti durante la compilazione.

Per altre informazioni sulle possibili cause e soluzioni per l'errore LNK2019, vedere la domanda Stack Overflow Cos'è un errore di simbolo esterno non risolto o con riferimento non definito e come si risolve?.

Strumenti di diagnosi

Può essere difficile stabilire il motivo per cui il linker non riesce trovare una definizione di un simbolo specifico. Spesso il problema deriva dal fatto di non avere incluso il codice nella compilazione oppure viene generato perché le opzioni di compilazione hanno creato nomi decorati diversi per i simboli esterni. Sono disponibili diversi strumenti e opzioni che consentono di diagnosticare un errore LNK2019.

  • L'opzione del linker /VERBOSE consente di determinare i file a cui il linker fa riferimento. Ciò consente di verificare se il file che contiene la definizione del simbolo è incluso nella compilazione.

  • Le opzioni /EXPORTS e /SYMBOLS dell'utilità DUMPBIN consentono di individuare quali simboli sono definiti nel file dll e nei file oggetto o di libreria. Verificare che i nomi decorati esportati corrispondano ai nomi esportati cercati dal linker.

  • L'utilità UNDNAME consente di visualizzare il simbolo esterno non decorato equivalente di un nome decorato.

Esempi

Di seguito sono riportati alcuni esempi di codice che causano un errore LNK2019 insieme alle informazioni su come correggere l'errore.

Un simbolo viene dichiarato ma non definito

L'esempio seguente genera l'errore LNK2019 perché un simbolo esterno viene dichiarato ma non definito :

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

Di seguito è riportato un altro esempio:

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

Se i e g non sono definiti in uno dei file inclusi nella compilazione, il linker genera l'errore LNK2019. È possibile correggere gli errori includendo il file del codice sorgente che contiene le definizioni come parte della compilazione. In alternativa, è possibile passare al linker i file obj o lib che contengono le definizioni.

Un membro dati statici viene dichiarato ma non definito

L'errore LNK2019 può verificarsi anche quando un membro dati statici viene dichiarato ma non definito. L'esempio seguente genera l'errore LNK2019 e mostra come risolverlo.

// 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;
}

I parametri della dichiarazione non corrispondono alla definizione

Il codice che richiama le funzioni modello deve contenere le dichiarazioni delle funzioni modello corrispondenti. Le dichiarazioni devono includere gli stessi parametri modello della definizione. L'esempio seguente genera l'errore LNK2019 per un operatore definito dall'utente e mostra come risolverlo.

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

template<class T> class 
Test {
   // The operator<< declaration does not 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
}

Definizioni di tipo wchar_t incoerenti

L'esempio seguente crea una DLL contenente un'esportazione che usa WCHAR, che viene risolta in wchar_t.

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

L'esempio seguente usa la DLL dell'esempio precedente e genera l'errore LNK2019 perché i tipi unsigned short * e WCHAR * non sono uguali.

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

int main() {
   func(0);
}

Per risolvere questo errore, modificare unsigned short in wchar_t o WCHAR oppure compilare LNK2019g.cpp usando /Zc:wchar_t-.