什么是未定义的参考/未解析的外部符号错误?常见原因是什么?如何解决/预防?
当前回答
当您使用错误的编译器构建程序时
如果您使用的是gcc或clang编译器套件,则应根据所使用的语言使用正确的编译器驱动程序。使用g++或clang++编译和链接C++程序。改用gcc或clang将导致对C++标准库符号的引用未定义。例子:
$ gcc -o test test.cpp
/usr/lib/gcc/x86_64-pc-linux-gnu/10.2.0/../../../../x86_64-pc-linux-gnu/bin/ld: /tmp/ccPv7MvI.o: warning: relocation against `_ZSt4cout' in read-only section `.text'
/usr/lib/gcc/x86_64-pc-linux-gnu/10.2.0/../../../../x86_64-pc-linux-gnu/bin/ld: /tmp/ccPv7MvI.o: in function `main': test.cpp:(.text+0xe): undefined reference to `std::cout'
/usr/lib/gcc/x86_64-pc-linux-gnu/10.2.0/../../../../x86_64-pc-linux-gnu/bin/ld: test.cpp:(.text+0x13): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)'
/usr/lib/gcc/x86_64-pc-linux-gnu/10.2.0/../../../../x86_64-pc-linux-gnu/bin/ld: /tmp/ccPv7MvI.o: in function `__static_initialization_and_destruction_0(int, int)':
test.cpp:(.text+0x43): undefined reference to `std::ios_base::Init::Init()'
/usr/lib/gcc/x86_64-pc-linux-gnu/10.2.0/../../../../x86_64-pc-linux-gnu/bin/ld: test.cpp:(.text+0x58): undefined reference to `std::ios_base::Init::~Init()'
/usr/lib/gcc/x86_64-pc-linux-gnu/10.2.0/../../../../x86_64-pc-linux-gnu/bin/ld: warning: creating DT_TEXTREL in a PIE
collect2: error: ld returned 1 exit status
其他回答
UNICODE定义不一致
Windows UNICODE构建时,TCHAR等被定义为wchar_t等。如果不使用UNICODE进行构建,则TCHAR被定义为char等。这些UNICODE和_UNICODE定义会影响所有“t”字符串类型;LPTSTR、LPCTSTR及其麋鹿。
构建一个定义了UNICODE的库,并试图将其链接到未定义UNICODE项目中,将导致链接器错误,因为TCHAR的定义将不匹配;char与wchar_t。
错误通常包括一个带有char或wchar_t派生类型的值的函数,这些类型也可能包括std::basic_string<>等。浏览代码中受影响的函数时,通常会引用TCHAR或std::basic_string<TCHAR>等。这是一个信号,表明代码最初用于UNICODE和多字节字符(或“窄”)构建。
要更正此问题,请使用UNICODE(和_UNICODE)的一致定义构建所有必需的库和项目。
这可以通过以下两种方式实现:;#定义UNICODE#定义UNICODE或在项目设置中;项目财产>常规>项目默认值>字符集或在命令行上;/DUNICODE/D-UNICODE
如果不打算使用UNICODE,请确保未设置定义,和/或在项目中使用了多字符设置,并始终应用。
不要忘记在“发布”和“调试”版本之间保持一致。
对的未定义引用WinMain@16或类似的“不寻常”main()入口点引用(特别是对于visual studio)。
您可能错过了使用实际IDE选择正确的项目类型。IDE可能希望将例如Windows应用程序项目绑定到这样的入口点函数(如上面缺失的引用中所指定的),而不是通常使用的int main(int argc,char**argv);签名
如果IDE支持普通控制台项目,您可能希望选择此项目类型,而不是windows应用程序项目。
下面是从真实世界问题中更详细地处理的案例1和案例2。
清理和重建
对构建进行“清理”可以清除以前的构建、失败的构建、不完整的构建和其他与构建系统相关的构建问题可能留下的“枯木”。
一般来说,IDE或构建将包含某种形式的“清理”功能,但这可能未正确配置(例如,在手动生成文件中)或可能失败(例如,中间或生成的二进制文件是只读的)。
一旦“清理”完成,请验证“清理”是否成功,以及所有生成的中间文件(例如自动生成文件)是否已成功删除。
这一过程可以被视为最后的手段,但往往是良好的第一步;特别是如果最近添加了与错误相关的代码(本地或从源存储库)。
在我的例子中,语法是正确的,但当一个类调用同一DLL中的第二个类时,我出现了错误。第二个类的CPP文件在visual studio中具有错误的财产->项类型,在我的例子中,它被设置为C/C++头,而不是正确的C/C++编译器,因此编译器在构建CPP文件时没有编译它,并导致错误LNK2019
下面是一个示例,假设语法正确,您应该通过更改财产中的项类型来获得错误
//class A header file
class ClassB; // FORWARD DECLERATION
class ClassA
{
public:
ClassB* bObj;
ClassA(HINSTANCE hDLL) ;
// member functions
}
--------------------------------
//class A cpp file
ClassA::ClassA(HINSTANCE hDLL)
{
bObj = new ClassB();// LNK2019 occures here
bObj ->somefunction();// LNK2019 occures here
}
/*************************/
//classB Header file
struct mystruct{}
class ClassB{
public:
ClassB();
mystruct somefunction();
}
------------------------------
//classB cpp file
/* This is the file with the wrong property item type in visual studio --C/C++ Header-*/
ClassB::somefunction(){}
ClassB::ClassB(){}
需要考虑的一些拼写错误:(我作为初学者经常遇到)
如果您使用的是类:请检查您是否没有在定义函数的cpp文件中的函数名之前忘记“classname::”。如果使用forward声明:请确保声明正确的类型。例如:如果要转发声明“结构”,请使用“结构”而不是“类”。