分享方式:


連結器工具錯誤 LNK2019

函式 『function』 中所參考的未解析外部符號 'symbol'

function 的編譯程式碼會參考或呼叫 symbol,但連結器在任何程式庫或物件檔案中找不到符號定義。

此錯誤訊息後面是嚴重錯誤 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 檔案中定義了一個符號,但未在 C++ 檔案中使用 extern "C" 宣告

編譯為 C 的檔案會建立 symbols 的裝飾名稱,與C++檔案中宣告的相同裝飾名稱不同 symbols ,除非您使用 extern "C" 修飾詞。 請確定宣告與每個符號的編譯連結相符。 同樣地,如果您在 C++ 檔案中定義將由 C 程式使用的符號,請在定義中使用 extern "C"

符號已定義為 static,而且稍後由檔案外部參考

不同於 C,C++ 中 全域常數static 連結。 若要解決這項限制,您可以在標頭檔中包含 const 初始設定,並將該標頭包含在 .cpp 檔案中,或者您可以將變數設為非常數,並使用常數參考來存取。

未定義類別的 static 成員

static 類別成員必須具有唯一的定義,否則將違反單一定義規則。 無法以內嵌進行定義的 static 類別成員,必須使用其完整名稱在一個來源檔案中加以定義。 如果未完全定義,則連結器會產生 LNK2019。

建置相依性只定義為方案中的專案相依性

在舊版的 Visual Studio 中,此層級的相依性已經足夠。 不過,從 Visual Studio 2010 開始,Visual Studio 需要專案對專案間的參考。 如果您的專案沒有專案對專案間的參考,您就有可能會收到這個連結器錯誤。 加入專案對專案間的參考來修正此問題。

未定義進入點

應用程式程式碼必須定義適當的進入點:針對主控台應用程式為 mainwmain,針對 Windows 應用程式為 WinMainwWinMain。 如需詳細資訊,請參閱 main 函式和命令列引數WinMain 函式。 若要使用自訂進入點,請指定 /ENTRY (進入點符號) 連接器選項。

您使用 Windows 應用程式設定來建置主控台應用程式

如果錯誤訊息類似於函式function_name中所參考的未解析外部符號WinMain,請使用 /SUBSYSTEM:CONSOLE 而非/SUBSYSTEM:WINDOWS連結。 如需此設定的詳細資訊,以及如何在 Visual Studio 中設定此屬性的指示,請參閱 /SUBSYSTEM (指定子系統)

連結至程式碼的程式庫和物件檔案必須針對與程式碼相同的架構進行編譯。 請確定您的專案參考的程式庫已針對與專案相同的架構進行編譯。 請確定 /LIBPATH其他程式庫目錄屬性指向為正確架構建置的程式庫。

您可以使用不同的編譯器選項,在不同的原始程式檔中用於函式內嵌

若使用在 .cpp 檔案中定義的內嵌函式,且又在不同的原始程式檔中混用函式內嵌編譯器選項,則可能會導致 LNK2019。 如需詳細資訊,請參閱 Function Inlining Problems

您可在其範圍外部使用自動變數

自動 (函式範圍) 變數只能在該函式的範圍內使用。 不能將這些變數宣告為 extern ,也不能在其他原始程式檔中加以使用。 如需範例,請參閱 Automatic (Function Scope) Variables

您呼叫內建函式,或傳遞至內建函式的引數類型在您的目標架構上並不支援

例如,如果您使用 AVX2 內部函數,但未指定 /ARCH:AVX2 編譯程式選項,編譯程式會假設內部函數是外部函式。 編譯器會產生具有相同名稱的外部符號呼叫做為內建,而非產生內嵌指令。 當連結器嘗試找出此遺漏函式的定義時,就會產生 LNK2019。 請確定您只使用內建和目標架構支援的類型。

您混合了使用和不使用原生 wchar_t 的程式碼

根據預設,於 Visual Studio 2005 中完成的 C++ 語言一致性工作讓 wchar_t 成為原生類型。 如果有些檔案未使用相同的 /Zc:wchar_t 設定進行編譯,則類型參考可能不會解析成相容的類型。 請確定所有程式庫和物件檔案中的 wchar_t 類型都相容。 從 wchar_t typedef 更新,或在編譯時使用一致的 /Zc:wchar_t 設定。

使用 Visual Studio 2015 之前的 Visual Studio 版本建置 static 程式庫,可能會在與 UCRT 連結時造成 LNK2019 錯誤。 UCRT 標頭檔 <stdio.h><conio.h><wchar.h> 現在會將許多 *printf**scanf* 變數定義為 inline 函式。 內嵌函式是由一組較小的通用函式所實作。 標準 UCRT 連結庫中無法使用內嵌函式的個別 exports 函式,只能匯出通用函式。 有一些方法可以解決這個問題。 我們建議的方法是使用您目前的 Visual Studio 版本重建舊版程式庫。 請確定程式庫程式碼會針對造成錯誤的 *printf**scanf* 函式定義使用標準標頭。 您無法重建的舊版程式庫的另一個選項是將 legacy_stdio_definitions.lib 新增至連結程式庫清單。 此連結庫檔案提供symbols*printf*內嵌在UCRT標頭中的和 *scanf* 函式。 如需詳細資訊,請參閱潛在升級問題概觀中的程式庫一節。

第三方程式庫問題和 vcpkg

如果您在嘗試將第三方程式庫設定為組建的一部分時看到此錯誤,請考慮使用 vcpkgvcpkg 是 C++ 套件管理員,會使用現有的 Visual Studio 工具來安裝和建置程式庫。 vcpkg 支援大型且一直成長的第三方程式庫清單。 設定成功建置為專案一部分所需的所有組態屬性和相依性。

診斷工具

有時候很難判斷為什麼連結器無法找到特定的符號定義。 問題通常是您尚未在組建中納入包含定義的程式碼。 或者,建置選項已為外部 symbols建立不同的裝飾名稱。 有些工具和選項可協助您診斷 LNK2019 錯誤。

  • /VERBOSE 連結器選項可協助您判斷連結器會參考哪些檔案。 此選項可協助您確認包含符號定義的檔案是否已包含在您的建置中。

  • 公用 /EXPORTS 程式的 和 /SYMBOLS 選項 DUMPBIN 可協助您探索 symbols .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() {}

除非 ig 在建置中包含的其中一個檔案定義,否則連結器會產生 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_tWCHAR,或使用 /Zc:wchar_t- 編譯 LNK2019g.cpp。

另請參閱

如需 LNK2019、LNK2001 和 LNK1120 錯誤之可能原因和解決方案的詳細資訊,請參閱堆疊溢位問題:What is an undefined reference/unresolved external symbol error and how do I fix it?