VS报错无法解析的外部符号...
我们在使用VS编译器编写C代码运行时提示:严重性 代码 说明 项目 文件 行 禁止显示状态错误 LNK2019 无法解析的外部符号 _main,函数 “int __cdecl invoke_main(void)” (?invoke_main@@YAHXZ) 中引用了该符号 StudyCProject E:\VisualStudioProjects\StudyCProject\StudyCProject\MSVCRTD.lib(exe_main.obj) 1
可能的原因:
有多种方法会造成此错误。 所有这些方法都涉及引用链接器无法解析或无法查找其定义的函数或变量。 编译器可以识别未声明符号的情况,但无法判断未定义符号的情况。 这是因为定义可能位于不同的源文件或库中。 如果引用了未定义的符号,链接器会生成未解析的外部 (external) 符号错误。
1.如果是在写代码阶段就报错了,那一般是因为包含目录没有设置对,导致程序无法找到外部库的函数定义.
2.而如果是自定义的函数找不到,则需要检查一下函数的拼写是否正确,或者函数在cpp中实现时有没有在函数名前面加上类的定义域(即类名::
)。还有特别需要注意的是,有时候自己定义的方法什么的都没有错,还是会报这个错误,及就是从定义可以跳转到声明,但是从声明跳转不到定义,编译器显示没有定义该函数,这个问题,也会报这个错误。
3.如果是运行时报错,常见的原因是你引用了某个库的函数,然后也正确添加了它的头文件路径,vs在写代码阶段可以找到这个函数的定义,但是,由于你没有添加或者正确设置这个库的lib或者dll路径的话,那么vs就会在运行时候报错无法解析的外部符号。
本人整理了一些报错的常见问题:
原因1:包含符号定义的源文件未编译
在vs中,确保将定义的符号编译为项目的一部分,检查中间是否正确匹配的.obj文件。
举例:比如我在qt上画了一个界面,然后将其.h和.cpp文件,迁移到我的工程文件下,运行就会报错,原因是我没有编译这两个文件,比如我自己的ui文件 #include "my_show" 一般情况下,编译器会自己生成一个“ui_my_show”的文件,如果没有编译迁移过来的文件,编译器就会报错,无法找到#include"ui_my_show"源文件,运行的话就会报错,无法解析外部符号。。。
原因2:包含符号定义的目标文件或库没有链接。
在 VS 中,确保包含符号定义的对象文件或库作为项目的一部分链接。 在命令行上,确保要链接的文件列表包含对象文件或库。
原因3:符号声明与定义不符
这个原因包括:拼写不一致、使用的该函数,该函数的类型或数量与函数定义不匹配。又或者声明的函数没有定义。(及就是在.h文件中声明了,但是在.cpp文件中没有实现。)
原因4:未定义类的static成员
static类成员必须具有唯一的定义,否则将违反单个定义规则。 无法以内联方式定义的 static 类成员必须通过使用其完全限定名称在一个源文件中进行定义。 如果根本没有进行定义,链接器会生成 LNK2019。
原因5:符号定义为 static,并随后在文件外部引用
不同于 C,在 C++ 中,全局常量 (constants) 具有 static 链接。 若要避开此限制,可以在头文件中包含 const 初始化,并在 .cpp 文件中包含该头文件,或者你可以使变量成为非 const 并使用 const 引用来进行访问。
原因6:未定义入口点
这个原因,要防止是不是将main()函数,写成mian()。
原因7:因模板类导致的LNK2019错误.
这个基于我们写代码,大多数会将.h和.cpp文件区分开,一个声明,一个定义。但是用到模板类的时候,大多数人还是会这样,这就造成LNK2019错误。
《C++编程思想》第15章(第300页)说明了原因:
模板定义很特殊。由template<…> 处理的任何东西都意味着编译器在当时不为它分配存储空间,它一直处于等待状态直到被一个模板实例告知。在编译器和连接器的某一处,有一机制能去掉指定模板的多重定义。所以为了容易使用,几乎总是在头文件中放置全部的模板声明和定义。
类模板导致错误的解决办法:
1.在主函数包含头文件时将实现类模板的函数也包含进来。如模板类在func.cpp中实现,那么就要在主函数中添加#include"func.cpp".
2.将模板类的定义及就是将实现方法和声明一同写在头文件中。
3.在实现模板类的文件中调用一下模板类,给予模板类一个具体化。
原因8:由于内联函数引起的LNK2019,无法解析的外部符号。
这个原因和上面的模板类的情况有些类似。通常编写函数时,会把声明放到头文件(*.h)中,而把函数定义放在源文件(*.cpp)中,在其他源文件中使用时包含对应的头文件即可。
但是内联函数(inline)不要定义在cpp文件中,因为我们通常都是包含头文件,而编译器在编译时会对内联函数进行展开操作,但是编译器只能在包含的头文件里搜索函数的定义体,如果头文件只有声明,显然编译器不知道该如何展开,于是就出错了。
第一种:
/*类内定义实现的即为内联函数,inline要不要都无所谓*/
Class A{
public:
int func(int a,int b){
return a+b;
}
};
/*func为内联函数*/
第二种:
/*类外定义实现的,类内声明可加可不加inline*/
Class A{
public:
int func(int a,int b);
};
inline int func(int a,int b){
return a+b;
}
/*很多资料所说定义应该放在源文件.cpp中,这是错误的,内联函数的定义应该放在头文件.h中*/
解决方法:内联函数类外定义的时候,定义应该和声明放在一起,都放在头文件.h中
原因9:属性页的配置平台和实际的运行平台是否一致:
原因10:还有一些无法加载上的依赖.lib
可以在头文件中直接添加进来。
#pragma comment(lib,"Rpcrt4.lib")
原因11:头文件问题
这个问题一般很难发现,我还是在项目当中遇到,我是在qt中,写一个界面类,然后将ui 、头文件还有.cpp文件迁移到我的工程文件下,(vs环境配置好的情况下),结果报错,找了一圈原因没有找到,最后找到我所引入的头文件,我转到#include<QWidget>下(编译器不报错),结果发现在#include<QWidget>文件下,只有一行#include"qwidegt.h"文件。 于是我直接将#include"qwidegt.h"引入我的头文件中,结果就不报LNK2019,无法解析外部符号错误。这也可能是我库没有配置好的原因。就是说如果遇到无法解决的,可以尝试找找头文件的原因。
原因12:特殊原因 宏定义
我们从贴上来的报错信息中可以看出,错误出现在PointCloudFilter类这里。于是,我们打开这个类的头文件,可以在开头的地方发现几行预处理代码,如下图所示。这是一个if_else的语句,大致意思是,如果定义了DLL_IMPLEMENT,则将DLL_API这个宏的值设置为输出dll文件,否则设置为输入dll文件。而这里,这个工程是要输出dll文件的,因此,我们需要在这些代码运行之前先定义好DLL_IMPLEMENT。
解决办法:就是要在vs 项目->属性->配置属性->C/C++->预处理器,加上DLL_IMPLEMENT宏定义。