天天看點

error LNK2019: 無法解析的外部符号 産生原因及修改方法

比較權威的解釋可參考微軟官方文檔https://docs.microsoft.com/en-us/previous-versions/799kze2z(v=vs.140)?redirectedfrom=MSDN

我的開發環境是Visual Studio 2013 Community,使用語言是C++,遇到這個問題時正在自己做DLL自己調用,在調用時出現這個錯誤。

這裡簡述官方文檔中列舉的常見發生原因,這裡結合我的經曆做一些記錄,加粗部分為原文内容:

  • 一、The object file or library that contains the definition of the symbol is not linked.(包含符号定義的目标檔案或庫檔案沒有被連結。)

解決方法是檢查是否正确指定了用到的.lib檔案或者.dll檔案等,它們是否被編譯完成(是否存在),還要注意版本是否一緻。可以檢查以下三個目錄中是否配置了所需要的檔案:

  1. 項目、屬性、配置屬性、VC++目錄、包含目錄:此處用于放置需要調用的外部的頭檔案夾。
  2. 項目、屬性、配置屬性、VC++目錄、庫目錄:此處用于放置需要調用的外部lib檔案夾。
  3. 項目、屬性、配置屬性、連結器、輸入、附加依賴項:此處用于記錄需要調用的外部lib檔案具體檔案名。

以上三個目錄是項目全局設定方法,可以用局部目錄如配置屬性中的C/C++目錄項代替,依具體使用需求而定。

說起來好像在質疑大家配置各項選項的能力,但是确實有可能發生這種情況。我見過以下三種情況:

  1. 寫DLL和調用DLL的項目分别使用了不同的平台,x64和x86混用。可以搭配出現“無法打開檔案”、“子產品計算機類型與目标計算機類型沖突”等問題
  2. DLL的輸出目錄改到了其他位置B,在修改前的預設路徑A下生成過一次,調用DLL的項目指向了修改前的預設路徑A下的檔案。發生這種情況的時候,可以看到部分符号(函數)不顯示錯誤,而另一部分符号無論怎麼改都是錯的,這種錯誤還常常發生在最後寫的一部分内容。
  3. release和debug版本沒對應好,用debug模式開發項目,卻把調用DLL的項目指向了以前生成的release版本的DLL,生成的DLL都是debug版本,下遊項目完全看不到更新,卻想調用新的内容,就出現錯誤,跟第二個一樣,發生這種情況的時候,可以看到部分符号(函數)是正确的,而另一部分符号無論怎麼改都是錯的,這種錯誤常常發生在最後寫的一部分内容。
  • 二、The declaration of the symbol is not spelled the same as the definition of the symbol.(符号在聲明和定義時拼寫不一緻)

在.h檔案和.cpp檔案中是否拼寫一緻,另外是否與調用時保持一緻。

  • 三、A function is used but the type or number of the parameters do not match the function definition.(調用函數時參數的類型和數量與定義不一緻)

我見過這種錯誤,它可能與“函數不接受n個參數”或類似的錯誤同時出現。

  • 四、A function or variable is declared but not defined.(函數或變量隻有聲明沒有定義)

在頭檔案中指給出了一個聲明,後面卻沒有給出相應的定義實作。常見于類的成員函數、靜态變量等。有可能是寫單例模式時在源檔案中函數定義處筆誤忘記加類名,如base* base::getInstance錯誤寫成base* getInstance,這使getInstance稱為全局函數,并非類成員函數的定義。也有可能寫構造函數析構函數想給一個空的函數體,卻錯誤的隻寫了一個分号,如class base{ base(); }; 改成一對大括号即可,如class base{ base(){} }; 也有可能是使用了内聯函數inline,某些情況下加入inline會直接導緻無法解析的外部符号,去掉即可通過。

  • 五、The calling convention is different between the function declaration and the function definition.(函數聲明和定義時的調用約定不一緻)

調用約定__cdecl,__stdcall,__fastcall,__vectorcall在函數的聲明和定義處不一緻,在錯誤提示處開頭就有顯示。

  • 六、A symbol is defined in a C file, but declared without using extern "C" in a C++ file.(在C檔案中定義的符号在C++檔案中聲明時沒有使用extern "C" )

相似地,在C++檔案中定義的符号,想在C項目中使用,應該在定義的地方加extern "C"

  • 七、A symbol is defined as static and then later referenced outside the file.(下面是此段原文,我解釋不了(╥﹏╥) )

In C++, unlike C, global constants have static linkage. To get around this limitation, you can include the const initializations in a header file and include that header in your .cpp files, or you can make the variable non-constant and use a constant reference to access it.

  • 八、A static member of a class is not defined. (靜态成員沒有定義)

一個典型的例子是使用單例模式時忘記在類外給靜态變量instance執行個體進行初始化。

  • 九、A build dependency is only defined as a project dependency in the solution.(有項目依賴時不能僅建立build依賴,需要建立project-to-project水準上的依賴)

沒用到,具體見官方文檔https://docs.microsoft.com/zh-cn/previous-versions/visualstudio/visual-studio-2015/ide/managing-references-in-a-project?view=vs-2015&redirectedfrom=MSDN

  • 十、You build a console application by using settings for a Windows application. (想建立一個控制台應用程式,卻建立了一個視窗應用程式)

如果提示錯誤是類似“unresolved external symbol WinMain referenced in function”,可以嘗試把/SUBSYSTEM:WINDOWS替換成/SUBSYSTEM:CONSOLE,在項目、屬性、配置屬性、連結器、系統、子系統。emmm這個問題比較嚴重,建議重建立立。

  • 十一、You use different compiler options for function inlining in different source files.(不同源檔案中的内聯函數用不用的編譯器選項編譯)

看起來這種情況也許是,如果有多個從源代碼編譯的依賴庫,要保證編譯時編譯器版本和選項一緻。

  • 十二、You use automatic variables outside their scope. (在作用域外使用了自動變量)
  • 十三、You call instrinsic functions or pass argument types to intrinsic functions that are not supported on your target architecture.(使用目标架構中沒有的内部函數)

比如想使用Intel Advanced Vector Extensions 2 instructions裡的内部函數,卻沒有指定/ARCH:AVX2,内部函數就當作了外部函數,是以找不到。(沒用過,翻譯的)

  • 十四、You mix code that uses native wchar_t with code that doesn't.

看到網上一些文章提到字元集不一緻導緻無法解析的外部符号,在項目、屬性、配置屬性、正常、項目預設值、字元集,看看幾個項目是否一緻。

這還不是全部,微軟推薦了這個網站https://stackoverflow.com/questions/12573816/what-is-an-undefined-reference-unresolved-external-symbol-error-and-how-do-i-fix

從上面一條一條來看,無非是配置設錯了,或者代碼漏寫了,調用的程式看不到它。

如果調用的内容是别人的發行版而且其他人可以用,那麼就是自己配置錯了,古話說得好,重新開機解決90%的問題,重裝解決99%的問題,再從零開始看一遍配置,在心裡模拟一遍項目的建立。可以對照第一、五、六、九、十、十一、十三、十四條。

如果是自己寫的依賴庫以前能用,而現在不能用:若剛剛修改了配置,參照上一條;如果沒有修改配置,那就是代碼問題。可以對照第二、三、四、七、八、十二條。穩住!

繼續閱讀