什么是未定义的参考/未解析的外部符号错误?常见原因是什么?如何解决/预防?
当前回答
对的未定义引用WinMain@16或类似的“不寻常”main()入口点引用(特别是对于visual studio)。
您可能错过了使用实际IDE选择正确的项目类型。IDE可能希望将例如Windows应用程序项目绑定到这样的入口点函数(如上面缺失的引用中所指定的),而不是通常使用的int main(int argc,char**argv);签名
如果IDE支持普通控制台项目,您可能希望选择此项目类型,而不是windows应用程序项目。
下面是从真实世界问题中更详细地处理的案例1和案例2。
其他回答
清理和重建
对构建进行“清理”可以清除以前的构建、失败的构建、不完整的构建和其他与构建系统相关的构建问题可能留下的“枯木”。
一般来说,IDE或构建将包含某种形式的“清理”功能,但这可能未正确配置(例如,在手动生成文件中)或可能失败(例如,中间或生成的二进制文件是只读的)。
一旦“清理”完成,请验证“清理”是否成功,以及所有生成的中间文件(例如自动生成文件)是否已成功删除。
这一过程可以被视为最后的手段,但往往是良好的第一步;特别是如果最近添加了与错误相关的代码(本地或从源存储库)。
需要考虑的一些拼写错误:(我作为初学者经常遇到)
如果您使用的是类:请检查您是否没有在定义函数的cpp文件中的函数名之前忘记“classname::”。如果使用forward声明:请确保声明正确的类型。例如:如果要转发声明“结构”,请使用“结构”而不是“类”。
使用带有代码运行程序扩展名和多个.c或.cpp文件的Visual Studio代码
所提供的Code Runner仅适用于具有单个源文件的编译程序。它不是为与多个源文件一起使用而设计的。您应该使用不同的扩展名,例如C/C++Makefile Project扩展名或CMake Tools扩展名,或者修复CodeRunner扩展名以处理多个文件,或者手动编辑.json配置文件。
指定相互依赖的链接库的顺序是错误的。
如果库相互依赖,则库的链接顺序也很重要。通常,如果库A依赖于库B,那么在链接器标志中,libA必须出现在libB之前。
例如:
// B.h
#ifndef B_H
#define B_H
struct B {
B(int);
int x;
};
#endif
// B.cpp
#include "B.h"
B::B(int xx) : x(xx) {}
// A.h
#include "B.h"
struct A {
A(int x);
B b;
};
// A.cpp
#include "A.h"
A::A(int x) : b(x) {}
// main.cpp
#include "A.h"
int main() {
A a(5);
return 0;
};
创建库:
$ g++ -c A.cpp
$ g++ -c B.cpp
$ ar rvs libA.a A.o
ar: creating libA.a
a - A.o
$ ar rvs libB.a B.o
ar: creating libB.a
a - B.o
编译:
$ g++ main.cpp -L. -lB -lA
./libA.a(A.o): In function `A::A(int)':
A.cpp:(.text+0x1c): undefined reference to `B::B(int)'
collect2: error: ld returned 1 exit status
$ g++ main.cpp -L. -lA -lB
$ ./a.out
再说一遍,顺序很重要!
在链接共享库时,请确保未隐藏使用的符号。
gcc的默认行为是所有符号都可见。但是,当使用选项-fvisibility=hidden构建转换单元时,只有标记为__attribute__((可见性(“默认”))的函数/符号在生成的共享对象中是外部的。
您可以通过调用以下命令来检查要查找的符号是否为外部符号:
# -D shows (global) dynamic symbols that can be used from the outside of XXX.so
nm -D XXX.so | grep MY_SYMBOL
隐藏/本地符号用小写符号类型的nm表示,例如t而不是代码段的“t”:
nm XXX.so
00000000000005a7 t HIDDEN_SYMBOL
00000000000005f8 T VISIBLE_SYMBOL
您还可以使用nm和选项-C来定义名称(如果使用了C++)。
与Windows DLL类似,可以使用define标记公共函数,例如DLL_public定义为:
#define DLL_PUBLIC __attribute__ ((visibility ("default")))
DLL_PUBLIC int my_public_function(){
...
}
大致对应于Windows的/MSVC版本:
#ifdef BUILDING_DLL
#define DLL_PUBLIC __declspec(dllexport)
#else
#define DLL_PUBLIC __declspec(dllimport)
#endif
有关可见性的更多信息可以在gcc wiki上找到。
当使用-fvisibility=hidden编译翻译单元时,生成的符号仍然具有外部链接(以大写符号类型显示,单位为nm),如果对象文件成为静态库的一部分,则可以毫无问题地用于外部链接。只有当对象文件链接到共享库中时,链接才会变为本地链接。
要查找对象文件中隐藏的符号,请运行:
>>> objdump -t XXXX.o | grep hidden
0000000000000000 g F .text 000000000000000b .hidden HIDDEN_SYMBOL1
000000000000000b g F .text 000000000000000b .hidden HIDDEN_SYMBOL2