Mr.J--C语言学习Errors:LNK2019

每日日常敲代码,日常看bug,错误提示:

这个错误提示第一次见到,心里表示很难受于是乎google一下:

可以在Linker Tools Error LNK2019中找到该主题的最新版本。

函数'function'中引用的未解析的外部符号'symbol'

链接器找不到symbol函数“ function”中使用的外部符号“ ” 的定义。

有许多问题可能导致此错误。本主题将帮助您确定原因并找到解决方案。

一个符号是编译器使用的函数或全局变量的名称。一个外部符号是用来指的是在不同来源或对象文件中定义的符号的名称。链接器必须为每个编译文件链接到应用程序或DLL时使用的每个函数或全局变量解析或找到外部符号的定义。如果链接器无法在任何链接文件中找到外部符号的匹配定义,则会生成LNK2019。

如果构建中未包含具有符号定义的对象或库文件,则会发生此错误。如果链接器搜索的符号名称与库中的符号名称或定义它的目标文件不匹配,也会发生这种情况。如果调用代码中的名称拼写错误,使用不同的大小写,使用不同的调用约定或指定不同的参数,则会发生这种情况。

使用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应用程序的设置来构建控制台应用程序。如果错误消息类似于函数中引用的未解析的外部符号WinMainfunction_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,因为已声明外部符号但未定义:

C ++

// LNK2019.cpp 
//使用以下
命令   编译:cl / EHsc LNK2019.cpp   // LNK2019预期   
extern  char B [100];   // B不可用于链接器   
int main(){  
   B [0] ='';   // LNK2019  
}  

这是另一个例子:

C ++

// LNK2019c.cpp 
//使用以下
命令   编译:cl / EHsc LNK2019c.cpp   // LNK2019预期   
extern  int i;  
extern  void g();  
void f(){  
   我++;  
   G();  
}  
int main(){}  

如果在构建中的某个文件中定义ig未定义,则链接器将生成LNK2019。您可以通过将包含定义的源代码文件包含在编译中来修复错误。或者,您可以传递包含定义的链接器.obj文件或.lib文件。

声明了静态数据成员但未定义

当声明静态数据成员但未定义静态数据成员时,也会发生LNK2019。以下示例生成LNK2019,并显示如何修复它。

C ++

// LNK2019b.cpp 
//使用以下
命令   编译:cl / EHsc LNK2019b.cpp   // LNK2019预期   
struct C {  
    static  int s;  
};  
  
//取消注释以下行以修复错误。  
// int C :: s;  
  
int main(){  
   C c;  
   C :: s = 1;  
}  

声明参数与定义不匹配

调用模板函数的代码必须具有匹配的模板函数声明。声明必须包含与定义相同的模板参数。以下示例在用户定义的运算符上生成LNK2019,并显示如何修复它。

C ++

// 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

C ++

// LNK2019g.cpp   
//编译:cl / EHsc / LD LNK2019g.cpp   
#include “windows.h”   
// WCHAR解析为wchar_t   
__declspec(dllexportvoid func(WCHAR *){}  

以下示例使用上一个示例中的DLL,并生成LNK2019,因为unsigned short *和WCHAR *类型不同。

C ++

// LNK2019h.cpp 
//使用以下
命令   编译:cl / EHsc LNK2019h LNK2019g.lib   // LNK2019期望   
__declspec(dllimportvoid func(unsigned  short *);  
  
int main(){  
   FUNC(0);  
}  

要解决此错误,请使用/ Zc:wchar_t-更改unsigned shortwchar_tWCHAR编译LNK2019g.cpp


经过细心察看发现函数名的参数与我在头函数定义的参数类型不匹配,一个bug已经消除,新的bug又来了...

猜你喜欢

转载自blog.csdn.net/Ms_yjk/article/details/82828000
今日推荐