链接器工具错误 LNK2001Linker Tools Error LNK2001

无法解析的外部符号 "symbol"unresolved external symbol "symbol"

已编译的代码对 符号 进行引用或调用。The compiled code makes a reference or call to symbol. 链接器搜索的任何库或对象文件中未定义该符号。The symbol isn't defined in any libraries or object files searched by the linker.

此错误消息后跟严重错误 LNK1120This error message is followed by fatal error LNK1120. 若要修复错误 LNK1120,请先修复所有 LNK2001 和 LNK2019 错误。To fix error LNK1120, first fix all LNK2001 and LNK2019 errors.

有多种方法可获取 LNK2001 错误。There are many ways to get LNK2001 errors. 所有这些方法都涉及到对链接器无法 解析 的函数或变量的 引用,或者查找的定义。All of them involve a reference to a function or variable that the linker can't resolve, or find a definition for. 当你的代码未 声明 符号,而未 定义 符号时,编译器可以确定它。The compiler can identify when your code doesn't declare a symbol, but not when it doesn't define one. 这是因为定义可能位于不同的源文件或库中。That's because the definition may be in a different source file or library. 如果代码引用符号,但从未定义过,则链接器将生成错误。If your code refers to a symbol, but it's never defined, the linker generates an error.

什么是无法解析的外部符号?What is an unresolved external symbol?

符号 是函数或全局变量的内部名称。A symbol is the internal name for a function or global variable. 它是在已编译的对象文件或库中使用或定义的名称的形式。It's the form of the name used or defined in a compiled object file or library. 全局变量是在为其分配存储的对象文件中定义的。A global variable is defined in the object file where storage is allocated for it. 函数在对象文件中定义,该对象文件中放置了函数体的已编译代码。A function is defined in the object file where the compiled code for the function body is placed. 外部符号 在一个对象文件中引用,但在不同的库或对象文件中定义。An external symbol is one referenced in one object file, but defined in a different library or object file. 导出的符号 是指由定义它的对象文件或库公开提供的符号。An exported symbol is one that's made publicly available by the object file or library that defines it.

若要创建应用程序或 DLL,每个使用的符号必须具有定义。To create an application or DLL, every symbol used must have a definition. 链接器必须 解析 或查找每个对象文件引用的每个外部符号的匹配定义。The linker must resolve, or find the matching definition for, every external symbol referenced by each object file. 如果链接器无法解析外部符号,则会生成错误。The linker generates an error when it can't resolve an external symbol. 这意味着链接器无法在任何链接的文件中找到匹配的已导出符号定义。It means the linker couldn't find a matching exported symbol definition in any of the linked files.

发生此错误的原因可能是:This error can occur:

  • 当项目缺少对库 ( 的引用时。LIB) 或对象 (。OBJ) 文件。When the project is missing a reference to a library (.LIB) or object (.OBJ) file. 若要解决此问题,请在项目中添加对所需库或对象文件的引用。To fix this issue, add a reference to the required library or object file to your project. 有关详细信息,请参阅 Lib 文件作为链接器输入For more information, see lib Files as linker input.

  • 当项目具有对库 ( 的引用时。LIB) 或对象 (。OBJ) 文件又需要另一个库中的符号。When the project has a reference to a library (.LIB) or object (.OBJ) file that in turn requires symbols from another library. 即使您不调用导致依赖关系的函数,也可能会发生这种情况。It may happen even if you don't call functions that cause the dependency. 若要解决此问题,请向项目添加对另一个库的引用。To fix this issue, add a reference to the other library to your project. 有关详细信息,请参阅 了解用于链接的传统模型:获取用于进行操作的符号For more information, see Understanding the classical model for linking: Taking symbols along for the ride.

  • 如果使用 /NODEFAULTLIB/zl 选项。If you use the /NODEFAULTLIB or /Zl options. 当你指定这些选项时,包含所需代码的库不会链接到项目中,除非你显式包含它们。When you specify these options, libraries that contain required code aren't linked into the project unless you've explicitly included them. 若要解决此问题,请显式包含在链接命令行上使用的所有库。To fix this issue, explicitly include all the libraries you use on the link command line. 如果在使用这些选项时发现许多缺少 CRT 或标准库函数名称,请在链接中显式包含 CRT 和标准库 Dll 或库文件。If you see many missing CRT or Standard Library function names when you use these options, explicitly include the CRT and Standard Library DLLs or library files in the link.

  • 如果使用 /clr 选项编译,则为。If you compile using the /clr option. 可能缺少对的引用 .cctorThere may be a missing reference to .cctor. 有关如何解决此问题的详细信息,请参阅 混合程序集的初始化For more information on how to fix this issue, see Initialization of mixed assemblies.

  • 如果在生成应用程序的调试版本时链接到发布模式库。If you link to the release mode libraries when building a debug version of an application. 同样,如果使用选项 /MTd/MDd 或定义 _DEBUG 并链接到发布库,则可能会预计许多潜在的无法解析的外部函数以及其他问题。Similarly, if you use options /MTd or /MDd or define _DEBUG and then link to the release libraries, you should expect many potential unresolved externals, among other problems. 将发布模式版本与调试库链接还会导致类似的问题。Linking a release mode build with the debug libraries also causes similar problems. 若要解决此问题,请确保在调试版本中使用调试库,并在零售版本中使用零售库。To fix this issue, make sure you use the debug libraries in your debug builds, and retail libraries in your retail builds.

  • 如果你的代码引用一个库版本中的符号,但你链接的是不同版本的库。If your code refers to a symbol from one library version, but you link a different version of the library. 通常,不能混合为不同版本的编译器生成的对象文件或库。Generally, you can't mix object files or libraries that are built for different versions of the compiler. 在一个版本中随附的库可能包含在其他版本随附的库中找不到的符号。The libraries that ship in one version may contain symbols that can't be found in the libraries included with other versions. 若要解决此问题,请在将对象文件和库与编译器的版本结合在一起之前生成它们。To fix this issue, build all the object files and libraries with the same version of the compiler before linking them together. 有关详细信息,请参阅 c + + 二进制兼容性 2015-2019For more information, see C++ binary compatibility 2015-2019.

  • 如果库路径过期,则为。If library paths are out of date. " 工具" > > 选项 "> VC + + 目录 " 对话框中的 " 库文件 " 对话框下,可以更改库的搜索顺序。The Tools > Options > Projects > VC++ Directories dialog, under the Library files selection, allows you to change the library search order. 项目的 "属性页" 对话框中的 "链接器" 文件夹可能还包含可能已过期的路径。The Linker folder in the project's Property Pages dialog box may also contain paths that could be out of date.

  • 如果安装了新的 Windows SDK (可能) 不同的位置。When a new Windows SDK is installed (perhaps to a different location). 必须更新库搜索顺序才能指向新位置。The library search order must be updated to point to the new location. 通常情况下,应将新的 SDK 包含的路径和 lib 目录放在默认 Visual C++ 位置之前。Normally, you should put the path to new SDK include and lib directories in front of the default Visual C++ location. 此外,包含嵌入路径的项目仍可指向有效但过期的旧路径。Also, a project containing embedded paths may still point to old paths that are valid, but out of date. 更新安装到不同位置的新版本添加的新功能的路径。Update the paths for new functionality added by the new version that's installed to a different location.

  • 如果在命令行中生成,并创建了自己的环境变量。If you build at the command line, and have created your own environment variables. 验证工具、库和头文件的路径是否为一致的版本。Verify that the paths to tools, libraries, and header files go to a consistent version. 有关详细信息,请参阅 为命令行生成设置路径和环境变量For more information, see Set the path and environment variables for command-line builds

编码问题Coding issues

此错误可由以下原因引起:This error can be caused by:

  • 源代码或模块定义中的大小写不匹配 ( .def) 文件。Mismatched case in your source code or module-definition (.def) file. 例如,如果您 var1 在一个 c + + 源文件中命名一个变量,然后尝试 VAR1 在另一个中访问它,则会生成此错误。For example, if you name a variable var1 in one C++ source file and try to access it as VAR1 in another, this error is generated. 若要解决此问题,请使用一致拼写和大小写的名称。To fix this issue, use consistently spelled and cased names.

  • 使用 函数内联的项目。A project that uses function inlining. 当您 inline 在源文件中定义函数而不是在头文件中定义函数时,就会发生这种情况。It can occur when you define the functions as inline in a source file, rather than in a header file. 内联函数在定义它们的源文件之外无法查看。Inlined functions can't be seen outside the source file that defines them. 若要解决此问题,请在声明它们的标头中定义内联函数。To fix this issue, define the inlined functions in the headers where they're declared.

  • 从 c + + 程序调用 C 函数,而不使用 extern "C" C 函数的声明。Calling a C function from a C++ program without using an extern "C" declaration for the C function. 编译器对 C 和 c + + 代码使用不同的内部符号命名约定。The compiler uses different internal symbol naming conventions for C and C++ code. 内部符号名称是链接器在解析符号时所查找的内容。The internal symbol name is what the linker looks for when resolving symbols. 若要解决此问题,请使用 c extern "C" + + 代码中使用的所有 c 函数声明的包装,这将导致编译器对这些符号使用 c 内部命名约定。To fix this issue, use an extern "C" wrapper around all declarations of C functions used in your C++ code, which causes the compiler to use the C internal naming convention for those symbols. 编译器选项 /tp/tc 会使编译器将文件分别编译为 C + + 或 C,无论文件扩展名是什么。Compiler options /Tp and /Tc cause the compiler to compile files as C++ or C, respectively, no matter what the filename extension is. 这些选项可能会导致内部函数名称与预期的名称不同。These options can cause internal function names different from what you expect.

  • 尝试引用不具有外部链接的函数或数据。An attempt to reference functions or data that don't have external linkage. 在 c + + 中,内联函数和 const 数据具有内部链接,除非显式指定为 externIn C++, inline functions and const data have internal linkage unless explicitly specified as extern. 若要解决此问题,请 extern 在定义源文件之外的符号上使用显式声明。To fix this issue, use explicit extern declarations on symbols referred to outside the defining source file.

  • 缺少函数体或变量定义。A missing function body or variable definition. 当你在代码中声明但不定义、变量、函数或类时,此错误很常见。This error is common when you declare, but don't define, variables, functions, or classes in your code. 编译器只需要一个函数原型或 extern 变量声明来生成对象文件,而不会出错,但链接器无法解析对该函数的调用或对该变量的引用,因为没有保留函数代码或变量空间。The compiler only needs a function prototype or extern variable declaration to generate an object file without error, but the linker can't resolve a call to the function or a reference to the variable because there's no function code or variable space reserved. 若要解决此问题,请确保在所链接的源文件或库中定义每个引用的函数和变量。To fix this issue, make sure to define every referenced function and variable in a source file or library you link.

  • 使用返回类型和参数类型的函数调用,或调用不与函数定义中的类型匹配的约定。A function call that uses return and parameter types or calling conventions that don't match the ones in the function definition. 在 c + + 对象文件中, 名称修饰 对调用约定、类或命名空间范围进行编码,并对函数的返回类型和参数类型进行编码。In C++ object files, Name decoration encodes the calling convention, class or namespace scope, and return and parameter types of a function. 编码的字符串将成为最终修饰函数名称的一部分。The encoded string becomes part of the final decorated function name. 链接器使用此名称来解析或匹配其他对象文件中对函数的调用。This name is used by the linker to resolve, or match, calls to the function from other object files. 若要解决此问题,请确保函数声明、定义和调用都使用相同的作用域、类型和调用约定。To fix this issue, make sure the function declaration, definition, and calls all use the same scopes, types, and calling conventions.

  • 当你在类定义中包括函数原型,但不 包括函数的实现 时,调用的 c + + 代码。C++ code you call, when you include a function prototype in a class definition, but don't include the implementation of the function. 若要解决此问题,请确保为调用的所有类成员提供定义。To fix this issue, be sure to provide a definition for all class members you call.

  • 尝试从抽象基类调用纯虚函数。An attempt to call a pure virtual function from an abstract base class. 纯虚函数没有基类实现。A pure virtual function has no base class implementation. 若要解决此问题,请确保已实现所有调用的虚拟函数。To fix this issue, make sure all called virtual functions are implemented.

  • 尝试使用在函数内声明的变量 (该函数作用域外) 的 局部变量Trying to use a variable declared within a function (a local variable) outside the scope of that function. 若要解决此问题,请删除对不在作用域中的变量的引用,或将变量移动到更高的作用域。To fix this issue, remove the reference to the variable that isn't in scope, or move the variable to a higher scope.

  • 生成 ATL 项目的发行版时,会生成一条消息,要求 CRT 启动代码是必需的。When you build a Release version of an ATL project, producing a message that CRT startup code is required. 若要解决此问题,请执行以下操作之一:To fix this issue, do one of the following,

    • _ATL_MIN_CRT从预处理器定义的列表中删除,以允许包含 CRT 启动代码。Remove _ATL_MIN_CRT from the list of preprocessor defines to allow CRT startup code to be included. 有关详细信息,请参阅 " 常规属性页 (项目) "。For more information, see General property page (Project).

    • 如果可能,请删除对需要 CRT 启动代码的 CRT 函数的调用。If possible, remove calls to CRT functions that require CRT startup code. 请改用其 Win32 等效项。Instead, use their Win32 equivalents. 例如,请使用 lstrcmp 而不是 strcmpFor example, use lstrcmp instead of strcmp. 需要 CRT 启动代码的已知函数是字符串和浮点函数的一部分。Known functions that require CRT startup code are some of the string and floating point functions.

一致性问题Consistency issues

在编译器供应商之间,甚至在同一编译器的不同版本之间没有 c + + 名称修饰 的标准。There's currently no standard for C++ name decoration between compiler vendors, or even between different versions of the same compiler. 使用不同编译器编译的对象文件不能使用相同的命名方案。Object files compiled with different compilers may not use the same naming scheme. 链接它们可能会导致错误 LNK2001。Linking them can cause error LNK2001.

混合不同模块上的内联和非内联编译选项可能会导致 LNK2001。Mixing inline and non-inline compile options on different modules can cause LNK2001. 如果在创建 c + + 库时打开了函数内联 (/Ob1/Ob2) 但描述函数的相应标头文件已关闭 (不 inline) 关键字,则会发生此错误。If a C++ library is created with function inlining turned on (/Ob1 or /Ob2) but the corresponding header file describing the functions has inlining turned off (no inline keyword), this error occurs. 若要解决此问题,请 inline 在其他源文件中包含的标头文件中定义函数。To fix this issue, define the functions inline in the header file you include in other source files.

如果使用 #pragma inline_depth 编译器指令,请确保将 值设置为2或更大,并确保还使用 /Ob1/Ob2 编译器选项。If you use the #pragma inline_depth compiler directive, make sure you've set a value of 2 or greater, and make sure you also use the /Ob1 or /Ob2 compiler option.

如果在创建纯资源 DLL 时省略了 LINK 选项/NOENTRY,则会出现此错误。This error can occur if you omit the LINK option /NOENTRY when you create a resource-only DLL. 若要解决此问题,请将/NOENTRY 选项添加到 link 命令。To fix this issue, add the /NOENTRY option to the link command.

如果在项目中使用不正确的/SUBSYSTEM 或/ENTRY 设置,则会发生此错误。This error can occur if you use incorrect /SUBSYSTEM or /ENTRY settings in your project. 例如,如果编写一个控制台应用程序并指定/SUBSYSTEM: WINDOWS,则会为生成一个无法解析的外部错误 WinMainFor example, if you write a console application and specify /SUBSYSTEM:WINDOWS, an unresolved external error is generated for WinMain. 若要解决此问题,请确保将选项与项目类型匹配。To fix this issue, make sure you match the options to the project type. 有关这些选项和入口点的详细信息,请参阅 /SUBSYSTEM/ENTRY 链接器选项。For more information on these options and entry points, see the /SUBSYSTEM and /ENTRY linker options.

导出的 .def 文件符号问题Exported .def file symbol issues

当找不到 .def 文件中列出的导出时,将出现此错误。This error occurs when an export listed in a .def file isn't found. 这可能是因为导出不存在、拼写错误或使用 c + + 修饰名。It could be because the export doesn't exist, is spelled incorrectly, or uses C++ decorated names. .Def 文件不采用修饰名。A .def file doesn't take decorated names. 若要解决此问题,请删除不需要的导出,并使用 extern "C" 导出的符号声明。To fix this issue, remove unneeded exports, and use extern "C" declarations for exported symbols.

使用修饰名查找错误Use the decorated name to find the error

C + + 编译器和链接器使用 名称修饰(也称为 名称重整)。The C++ compiler and linker use Name Decoration, also known as name-mangling. 名称修饰对其符号名称中的变量类型的额外信息进行编码。Name decoration encodes extra information about the type of a variable in its symbol name. 函数的符号名称对其返回类型、参数类型、作用域和调用约定进行编码。The symbol name for a function encodes its return type, parameter types, scope, and calling convention. 此修饰名是链接器搜索以解析外部符号的符号名称。This decorated name is the symbol name the linker searches for to resolve external symbols.

如果函数或变量的声明与函数或变量的定义不 完全 匹配,则可能会导致链接错误。A link error can result if the declaration of a function or variable doesn't exactly match the definition of the function or variable. 这是因为任何差异都会成为要匹配的符号名称的一部分。That's because any difference becomes part of the symbol name to match. 即使在调用代码和定义代码中使用相同的头文件,也可能发生此错误。The error can happen even if the same header file is used in both the calling code and the defining code. 出现这种情况的一种方法是使用不同的编译器标志来编译源文件。One way it may occur is if you compile the source files by using different compiler flags. 例如,如果你的代码编译为使用 __vectorcall 调用约定,但你链接到的库要求客户端使用默认 __cdecl 或调用约定来调用它 __fastcallFor example, if your code is compiled to use the __vectorcall calling convention, but you link to a library that expects clients to call it using the default __cdecl or __fastcall calling convention. 在这种情况下,由于调用约定不同,因此符号不匹配。In this case, the symbols don't match because the calling conventions are different.

为了帮助你找到原因,错误消息会显示两个名称版本。To help you find the cause, the error message shows you two versions of the name. 它同时显示 "友好名称"、"在源代码中使用的名称" 和 "修饰名" (括号) 。It displays both the "friendly name," the name used in source code, and the decorated name (in parentheses). 不需要知道如何解释修饰名。You don't need to know how to interpret the decorated name. 你仍可以搜索并将其与其他修饰名称进行比较。You can still search for and compare it with other decorated names. 命令行工具可帮助查找和比较预期符号名称和实际符号名称:Command-line tools can help to find and compare the expected symbol name and the actual symbol name:

  • 此处的 DUMPBIN 命令行工具的 /EXPORTS/SYMBOLS 选项非常有用。The /EXPORTS and /SYMBOLS options of the DUMPBIN command-line tool are useful here. 它们可帮助你发现 .dll 和对象或库文件中定义了哪些符号。They can help you discover which symbols are defined in your .dll and object or library files. 您可以使用符号列表来验证导出的修饰名称是否匹配链接器搜索的修饰名称。You can use the symbols list to verify that the exported decorated names match the decorated names the linker searches for.

  • 在某些情况下,链接器只能报告符号的修饰名。In some cases, the linker can only report the decorated name for a symbol. 可以使用 UNDNAME 命令行工具来获取修饰名的未修饰形式。You can use the UNDNAME command-line tool to get the undecorated form of a decorated name.

其他资源Additional resources

有关详细信息,请参阅 Stack Overflow 问题 "什么是未定义的引用/未解析的外部符号错误以及如何修复此错误?"For more information, see the Stack Overflow question "What is an undefined reference/unresolved external symbol error and how do I fix it?".