Mr.J--C語言學習Errors:LNK2019
每日日常敲程式碼,日常看bug,錯誤提示:
這個錯誤提示第一次見到,心裡表示很難受於是乎google一下:
可以在Linker Tools Error LNK2019中找到該主題的最新版本。
函式'function'中引用的未解析的外部符號'symbol'
連結器找不到symbol
函式“ function
”中使用的外部符號“ ” 的定義。
有許多問題可能導致此錯誤。本主題將幫助您確定原因並找到解決方案。
一個符號是編譯器使用的函式或全域性變數的名稱。一個外部符號是用來指的是在不同來源或物件檔案中定義的符號的名稱。連結器必須為每個編譯檔案連結到應用程式或DLL時使用的每個函式或全域性變數解析
如果構建中未包含具有符號定義的物件或庫檔案,則會發生此錯誤。如果連結器搜尋的符號名稱與庫中的符號名稱或定義它的目標檔案不匹配,也會發生這種情況。如果呼叫程式碼中的名稱拼寫錯誤,使用不同的大小寫,使用不同的呼叫約定或指定不同的引數,則會發生這種情況。
使用C ++連結的程式碼使用名稱修飾(也稱為名稱修改)來編碼有關變數或函式型別的額外資訊,並在符號名稱中呼叫約定。該修飾名是連結器搜尋以解析外部符號的名稱。因為型別資訊成為符號的修飾名稱的一部分,所以如果使用它的外部符號的宣告與定義它的符號的宣告不匹配,則可能導致LNK2019。為了幫助您找到錯誤原因,錯誤訊息顯示“友好名稱”,原始碼中使用的名稱以及未解析外部符號的修飾名稱(括號中)。您不需要知道如何翻譯裝飾名稱以便能夠將其與其他裝飾名稱進行比較。
常見問題
以下是導致LNK2019的一些常見問題:
-
包含符號定義的目標檔案或庫未連結。在Visual Studio中,驗證包含該定義的原始檔是否已構建並連結為專案的一部分。在命令列上,驗證是否已編譯包含該定義的原始檔,以及生成的目標檔案是否包含在要連結的檔案列表中。
-
符號的宣告與拼寫的定義拼寫不同。驗證宣告和定義中使用的拼寫和大小寫是否正確,以及使用或呼叫符號的位置。
-
使用了一個函式,但引數的型別或數量與函式定義不匹配。函式宣告必須與定義匹配。驗證函式呼叫是否與宣告匹配,以及宣告是否與定義匹配。呼叫模板函式的程式碼還必須具有匹配的模板函式宣告,其中包含與定義相同的模板引數。有關模板宣告不匹配的示例,請參閱示例部分中的示例LNK2019e.cpp。
-
聲明瞭函式或變數但未定義。這通常意味著標頭檔案中存在宣告,但未實現匹配的定義。對於成員函式或靜態資料成員,實現必須包括類作用域選擇器。有關示例,請參閱缺少函式體或變數。
-
函式宣告和函式定義之間的呼叫約定是不同的。呼叫約定(__cdecl,__stdcall,__fastcall,或__vectorcall)被編碼為裝飾名稱的一部分。驗證呼叫約定是否相同。
-
符號在C檔案中定義,但在C ++檔案中未使用extern“C”進行宣告。編譯為C的檔案中定義的符號具有與C ++檔案中宣告的符號不同的裝飾名稱,除非您使用extern“C”修飾符。驗證宣告是否與每個符號的編譯連結匹配。
同樣,如果在C程式
extern "C"
中定義將由C程式使用的符號,請在定義中使用。 -
符號定義為靜態,然後在檔案外引用。在C ++中,與C不同,全域性常量具有
static
連結。要解決此限制,可以const
在標頭檔案中包含初始化並在.cpp檔案中包含該頭,或者可以使變數非常量並使用常量引用來訪問它。 -
未定義類的靜態成員。靜態類成員必須具有唯一定義,否則將違反單定義規則。無法在內定義的靜態類成員必須使用其完全限定名稱在一個原始檔中定義。如果根本沒有定義,連結器將生成LNK2019。
-
構建依賴關係僅在解決方案中定義為專案依賴關係。在早期版本的Visual Studio中,此級別的依賴性已足夠。但是,從Visual Studio 2010開始,Visual Studio需要專案到專案的引用。如果您的專案沒有專案到專案引用,則可能會收到此連結器錯誤。新增專案到專案的引用以修復它。
-
您可以使用Windows應用程式的設定來構建控制檯應用程式。如果錯誤訊息類似於函式中引用的未解析的外部符號WinMain
function_name
,則使用/ SUBSYSTEM:CONSOLE而不是/ SUBSYSTEM:WINDOWS進行連結。有關此設定的詳細資訊,以及有關如何在Visual Studio中設定此屬性的說明,請參閱/ SUBSYSTEM(指定子系統)。 -
您可以使用不同的編譯器選項在不同的原始檔中進行函式內聯。使用.cpp檔案中定義的行內函數和混合函式內聯不同原始檔中的編譯器選項可能會導致LNK2019。有關更多資訊,請參閱函式內聯問題。
-
您在其範圍之外使用自動變數。自動(函式範圍)變數只能在該函式的範圍內使用。無法
extern
在其他原始檔中宣告和使用這些變數。有關示例,請參見自動(函式範圍)變數。 -
您可以呼叫instrinsic函式或將引數型別傳遞給目標體系結構不支援的內部函式。例如,如果使用AVX2內在函式,但未指定/ ARCH:AVX2編譯器選項,則編譯器會假定內在函式是外部函式。編譯器不會生成內聯指令,而是生成對與內在符號同名的外部符號的呼叫。當連結器嘗試查詢此缺失函式的定義時,它會生成LNK2019。確認您僅使用目標體系結構支援的內在函式和型別。
-
您將使用本機wchar_t的程式碼與不使用本機wchar_t的程式碼混合在一起。在Visual C ++ 2005中完成的C ++語言一致性工作
wchar_t
預設情況下是一個本機型別。必須使用/ Zc:wchar_t-編譯器選項生成與使用早期版本的Visual C ++編譯的庫和目標檔案相容的程式碼。如果並非所有檔案都使用相同的/ Zc:wchar_t設定進行編譯,則型別引用可能無法解析為相容型別。wchar_t
通過更新所使用的型別或在編譯時使用consistent / Zc:wchar_t設定來驗證所有庫和目標檔案中的型別是否相容。
有關LNK2019的可能原因和解決方案的更多資訊,請參閱堆疊溢位問題什麼是未定義的參考/未解決的外部符號錯誤以及如何解決?。
診斷工具
很難說為什麼連結器找不到特定的符號定義。通常問題是您沒有在構建中包含程式碼,或者構建選項為外部符號建立了不同的裝飾名稱。有幾個工具和選項可以幫助您診斷LNK2019錯誤。
-
該/ VERBOSE連結器選項可以幫助你確定哪些檔案連結引用。這可以幫助您驗證包含符號定義的檔案是否包含在您的構建中。
-
DUMPBIN實用程式的/ EXPORTS和/ SYMBOLS選項可以幫助您發現.dll和物件或庫檔案中定義的符號。驗證匯出的修飾名稱是否與連結器搜尋的修飾名稱匹配。
-
UNDNAME實用程式可以顯示裝飾名稱的等效未修飾外部符號。
例子
以下是導致LNK2019錯誤的幾個程式碼示例,以及有關如何修復錯誤的資訊。
宣告符號但未定義
以下示例生成LNK2019,因為已宣告外部符號但未定義:
// LNK2019.cpp
//使用以下
命令 編譯:cl / EHsc LNK2019.cpp // LNK2019預期
extern char B [100]; // B不可用於連結器
int main(){
B [0] =''; // LNK2019
}
這是另一個例子:
// LNK2019c.cpp
//使用以下
命令 編譯:cl / EHsc LNK2019c.cpp // LNK2019預期
extern int i;
extern void g();
void f(){
我++;
G();
}
int main(){}
如果在構建中的某個檔案中定義i
和g
未定義,則連結器將生成LNK2019。您可以通過將包含定義的原始碼檔案包含在編譯中來修復錯誤。或者,您可以傳遞包含定義的連結器.obj檔案或.lib檔案。
聲明瞭靜態資料成員但未定義
當宣告靜態資料成員但未定義靜態資料成員時,也會發生LNK2019。以下示例生成LNK2019,並顯示如何修復它。
// LNK2019b.cpp
//使用以下
命令 編譯:cl / EHsc LNK2019b.cpp // LNK2019預期
struct C {
static int s;
};
//取消註釋以下行以修復錯誤。
// int C :: s;
int main(){
C c;
C :: s = 1;
}
宣告引數與定義不匹配
呼叫模板函式的程式碼必須具有匹配的模板函式宣告。宣告必須包含與定義相同的模板引數。以下示例在使用者定義的運算子上生成LNK2019,並顯示如何修復它。
// LNK2019e.cpp
//使用以下
命令 編譯:cl / EHsc LNK2019e.cpp //預計LNK2019
#include <iostream>
使用 名稱空間 std;
template < class T> 類
測試{
// operator <<宣告與下面的定義不匹配:
friend ostream&operator <<(ostream&,Test&);
//要修復,請使用以下內容替換上面的行:
// template <typename T> friend ostream&operator <<(ostream&,Test <T>&);
};
template < typename T>
ostream&operator <<(ostream&os,Test <T>&tt){
return os;
}
int main(){
測試< int > t;
cout << “測試:” << t << endl; // LNK2019未解析外部
}
wchar_t型別定義不一致
下面的示例建立一個具有匯出使用的DLL WCHAR
,該解析將解析為wchar_t
。
// LNK2019g.cpp
//編譯:cl / EHsc / LD LNK2019g.cpp
#include “windows.h”
// WCHAR解析為wchar_t
__declspec(dllexport)void func(WCHAR *){}
以下示例使用上一個示例中的DLL,並生成LNK2019,因為unsigned short *和WCHAR *型別不同。
// LNK2019h.cpp
//使用以下
命令 編譯:cl / EHsc LNK2019h LNK2019g.lib // LNK2019期望
__declspec(dllimport)void func(unsigned short *);
int main(){
FUNC(0);
}
要解決此錯誤,請使用/ Zc:wchar_t-更改unsigned short
為wchar_t
或WCHAR
編譯LNK2019g.cpp。
經過細心察看發現函式名的引數與我在頭函式定義的引數型別不匹配,一個bug已經消除,新的bug又來了...