链接器工具错误 LNK2005

对象中已定义的符号

多次定义了符号 symbol

该错误之后为错误 LNK1169

可能的原因和解决方案

通常,此错误意味着违反了唯一定义规则,该规则允许对给定对象文件中使用的任何模板、函数、类型或对象进行唯一定义,且允许在整个可执行文件中对外部可见对象或函数进行唯一定义

以下是导致此错误的一些常见原因。

  • 头文件定义变量时,可能会发生此错误。 例如,如果在项目的多个源文件中包含此头文件,会导致错误:

    // LNK2005_global.h
    int global_int;  // LNK2005
    

    可能的解决方案包括:

    • 在头文件: extern int global_int; 中声明变量 extern,然后定义它并选择性地在唯一的源文件: int global_int = 17; 中进行初始化。 此变量现在是全局变量,可通过将其声明为 extern(例如,通过包含头文件)在任何源文件中使用。 对于必须是全局变量的变量,建议使用此解决方案,但良好的软件工程做法可以最大程度地减少全局变量。

    • 将变量声明为 staticstatic int static_int = 17;。 这将定义的范围限制为当前对象文件,并允许多个对象文件拥有自己的变量副本。 不建议在头文件中定义静态变量,因为可能会与全局变量混淆。 建议将静态变量定义移动到使用它的源文件。

    • 将变量声明为 selectany__declspec(selectany) int global_int = 17;。 这会使链接器选择唯一定义以供所有外部引用使用,并丢弃其余定义。 组合导入库时,此解决方案有时很有用。 在其他情况下,不建议使用它来避免链接器错误。

  • 头文件定义的函数不是 inline 时,可能会发生此错误。 如果将此头文件包含在多个源文件中,则会获得可执行文件中的函数的多个定义。

    // LNK2005_func.h
    int sample_function(int k) { return 42 * (k % 167); }  // LNK2005
    

    可能的解决方案包括:

    • inline 关键字添加到函数中:

      // LNK2005_func_inline.h
      inline int sample_function(int k) { return 42 * (k % 167); }
      
    • 从头文件中删除函数正文,只留声明,然后在唯一的源文件中实现函数:

      // LNK2005_func_decl.h
      int sample_function(int);
      
      // LNK2005_func_impl.cpp
      int sample_function(int k) { return 42 * (k % 167); }
      
  • 如果在头文件中的类声明之外定义成员函数,也会发生此错误:

    // LNK2005_member_outside.h
    class Sample {
    public:
        int sample_function(int);
    };
    int Sample::sample_function(int k) { return 42 * (k % 167); }  // LNK2005
    

    要解决此问题,请在类中移动成员函数定义。 类声明中定义的成员函数是隐式内联的。

    // LNK2005_member_inline.h
    class Sample {
    public:
        int sample_function(int k) { return 42 * (k % 167); }
    };
    
  • 如果链接多个版本的标准库或 CRT,则可能会发生此错误。 例如,如果尝试将零售和调试 CRT 库,或库的静态和动态版本,或标准库的两个不同版本链接到可执行文件,则可能会多次报告此错误。 要解决此问题,请从链接命令中删除每个库的所有副本,但有一个副本除外。 不建议在同一可执行文件中混合零售和调试库,或者不同版本的库。

    要使链接器使用默认库以外的库,请在命令行中指定要使用的库,然后使用 /NODEFAULTLIB 选项禁用默认库。 在 IDE 中,添加对项目的引用以指定要使用的库,然后打开项目的“属性页”对话框,并在“链接器”、“输入”属性页中设置“忽略所有默认库”或“忽略特定默认库”属性以禁用默认库

  • 如果使用 /clr 选项时混合使用静态库和动态库,则可能会出现此错误。 例如,如果生成 DLL 并在在静态 CRT 中建立链接的可执行文件中使用,则可能会发生此错误。 要解决此问题,请仅对整个可执行文件以及生成并在可执行文件中使用的任何库使用静态库或动态库。

  • 如果该符号为封装函数(通过用 /Gy 编译创建)且包含在多个文件中,但在各编译间已改变,则可能会发生此错误。 要解决此问题,请重新编译包含封装函数的所有文件。

  • 如果以不同的形式在不同库中的两个成员对象中定义了该符号,并且使用了这两个成员对象,则可能会发生此错误。 如果库是静态链接的,解决此问题的一种方法是仅使用一个库中的成员对象,并首先在链接器命令行中添加该库。 要使用这两个符号,必须创建区分方法。 例如,如果可以从源生成库,则可以将每个库包装在唯一的命名空间中。 另外,可以新建包装器库来使用唯一名称包装对某一原始库的引用,将新库链接到原始库,然后将可执行文件链接到新库而不是原始库。

  • 如果 extern const 变量定义了两次,且在每个定义中具有不同的值,则可能会发生此错误。 要解决此问题,请仅定义一次常量,或者使用命名空间或 enum class 定义来区分常量。

  • 如果将 uuid.lib 与定义 GUID 的其他 .lib 文件(例如 oledb.lib 和 adsiid.lib)一起使用,则可能会发生此错误。 例如:

    oledb.lib(oledb_i.obj) : error LNK2005: _IID_ITransactionObject
    already defined in uuid.lib(go7.obj)
    

    要解决此问题,请将 /FORCE:MULTIPLE 添加到链接器命令行选项,并确保 uuid.lib 是引用的第一个库。