Troubleshooting LNK2001 or L2029 Unresolved External Errors

本文详细解析了LNK2001错误产生的原因及常见触发因素,包括符号未定义、函数体缺失等问题,并提供了如何避免这些错误的具体建议。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

SUMMARY

The linker issues an Unresolved External message if it cannot resolve the address of a function while building a project.

LNK2001: unresolved external symbol '__symbol'

The '__symbol' might be a label, a variable, or a function name.

---------------------------------------------------------------------
下面的链接器行为解释了为什么会发生这种错误,这是一个简单的模型,内部实现可能因编译器而异,但不影响说明。

 

在编译源文件的时候, 会为每个object module创建一个名称表格以便在不同的object module之间进行符号引用。公共符号表(Public Symbols Table (PST)),它包含着一个对应object module的所有的公共符号,这里的所谓公共符号,即其它module可以引用的符号——比如全局函数和变量。每个object module亦含有一个未解析的符号表格(Unresolved Symbol Table (UST)),这里包含着本module需要解析的一列符号。

 

如果没有链接错误发生,则链接器会生成一个.map文件,这里列出了“刚刚链接在一起的所有object modules”中的所有公共符号(a combined PST table)。

 

要生成.map文件:
16位Visual C++使用/MAP:FULL linker option
Visual Workbench->Options menu->project->Linker->category: Miscellaneous, ->place /MAP:FULL in the Other Options edit box

 

32位Visual C++使用 /MAP:<filename> option,例如在VC4.0中
Build menu->Settings->Linker tab->Category: General->select the Generate Map File check box

图1:

链接器解析

链接器使用工程中所有object和library文件的PST和UST来匹配符号名称。如果链接器在某UST中找到了一个符号,但是在所有的PST文件中都找不到与之对应的项,它就会发出一个 "Unresolved External"错误消息。例如,在图1中,链接其不能解析函数func3()的地址,因此发出了"Unresolved External"错误消息。

 

经常触发"Unresolved External"错误消息的原因:

 

Missing Object Files or Libraries Object 或 Libraries 文件缺失


Missing Function Body or Variable 函数体或者变量缺失


Symbol Can't be Found in the Libraries or Object Modules 库或者Object模块中找不到需要的符号

 

Case Sensitivity 大小写

 

Name Decoration 命名


A Symbol Is Not Public 某符号非公共


Scoping Problems and Pure Virtual Functions 作用域问题或者纯虚函数问题


Function Inlining 函数内联


Wrong Compiler Options or Mixing Incompatible Libraries 错误的编译器选项

 

Missing Function Body or Variable 函数体或者变量缺失

如果只提供函数原型,连接器就无法解析任何对此函数的调用,因为它没有定义。结果,该函数就没有被放入combined PST table的表格中。与此类似,如果某外部变量被声明但是没有定义的话,会发生同样的问题。例如:

 

当使用C++时,确保在类的定义中,为类的每个成员函数都提供函数定义,而非只有原型。如果你在类定义的外部定义了该函数,请确保以如下方式Classname::MemberFunction在函数名前包含类的名称。参见“作用域和纯虚数问题”

 

当使用C++时,如某个C++程序要调用一个C函数,或者一个C程序要调用C++函数,请使用extern "C"。extern "C"对那些全局的C++函数强制使用C命名方式,这使得它们可以被C程序调用。
  void CALLTYPE test(void)
  C naming convention
   (__cdecl)                  _test         
?test@@YAXXZ
Be aware of compiler switches like /Tp or /Tc that force a file to be compiled as a C (/Tc) or C++ (/Tp) file regardless of the filename extension, or you may get different function names than you expected.

 

Function prototypes with mismatched parameters can also cause unresolved external errors. Many name-decoration schemes incorporate the parameters of a function into the final decorated function name. Calling a function with parameter types that do not match those in the function definition may also cause this error. This can be a problem in other languages, like FORTRAN, which may also add name decoration to a function.

 

在下面的例子中,头文件中的函数原型与函数定义不匹配,这会引发问题的。

符号非公共:

只有全局函数和变量会被放在目标文件的PST表中,试图访问如下的类型变量可能会产生问题。
Static functions/variables: 静态函数或者静态变量

静态函数或者静态变量的作用域只在本文件内,如试图从文件外访问这些符号,会引起外部解析错误。例如:

Automatic (function scope) variables: 自动变量(函数内部)

函数内部声明的自动变量只能在函数内部使用!

Global Constants in C++: C++中的全局常量

C++中的全局常量执行静态链接,这与C是不同的。如果你是如在多个C++文件中使用一个全局常量,你就会遇到这个错误,见如下代码示例:

一种折中办法,是将const的初始化放在头文件中,然后需要时包含该头文件即可,可以把它当作函数原型那样去使用。另外一种方法是使它成为非常量,使用的时候进行常量引用即可。

 

C++中的全局内联函数

。。。

抽象基类

。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值